diff --git a/meteoinfo-common/src/main/java/org/meteoinfo/common/PointD.java b/meteoinfo-common/src/main/java/org/meteoinfo/common/PointD.java
index 3c23ebaf..e5866ebc 100644
--- a/meteoinfo-common/src/main/java/org/meteoinfo/common/PointD.java
+++ b/meteoinfo-common/src/main/java/org/meteoinfo/common/PointD.java
@@ -33,7 +33,8 @@ public class PointD implements Cloneable{
}
/**
- * Contructor
+ * Constructor
+ *
* @param x
* @param y
*/
@@ -46,6 +47,22 @@ public class PointD implements Cloneable{
//
//
+ /**
+ * To double array
+ * @return Double array
+ */
+ public double[] toArray() {
+ return new double[]{X, Y};
+ }
+
+ /**
+ * To float array
+ * @return Float array
+ */
+ public float[] toFloatArray() {
+ return new float[]{(float) X, (float) Y};
+ }
+
/**
* Equals of two pointDs
* @param p PointD
diff --git a/meteoinfo-common/src/main/java/org/meteoinfo/common/colors/ColorUtil.java b/meteoinfo-common/src/main/java/org/meteoinfo/common/colors/ColorUtil.java
index 9baf2e1a..956034a1 100644
--- a/meteoinfo-common/src/main/java/org/meteoinfo/common/colors/ColorUtil.java
+++ b/meteoinfo-common/src/main/java/org/meteoinfo/common/colors/ColorUtil.java
@@ -137,6 +137,15 @@ public class ColorUtil {
//
//
+ /**
+ * Convert color r,g,b to hex string
+ * @param color The color
+ * @return Hex string
+ */
+ public static String toHex(Color color) {
+ return String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue());
+ }
+
/**
* Convert a color to hex string
*
diff --git a/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java b/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java
index c685b7dd..bd43931c 100644
--- a/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java
+++ b/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java
@@ -67,7 +67,7 @@ import java.util.zip.ZipInputStream;
public static String getVersion(){
String version = GlobalUtil.class.getPackage().getImplementationVersion();
if (version == null || version.equals("")) {
- version = "3.7.8";
+ version = "3.7.9";
}
return version;
}
diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONReader.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONReader.java
new file mode 100644
index 00000000..098b897e
--- /dev/null
+++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONReader.java
@@ -0,0 +1,77 @@
+package org.meteoinfo.geo.io;
+
+import org.meteoinfo.common.colors.ColorUtil;
+import org.meteoinfo.geo.layer.VectorLayer;
+import org.meteoinfo.geometry.io.geojson.*;
+import org.meteoinfo.geometry.legend.ColorBreak;
+import org.meteoinfo.geometry.legend.LegendScheme;
+import org.meteoinfo.geometry.legend.LegendType;
+import org.meteoinfo.geometry.legend.PolygonBreak;
+import org.meteoinfo.geometry.shape.Shape;
+import org.meteoinfo.geometry.shape.ShapeTypes;
+import org.meteoinfo.ndarray.DataType;
+
+import java.awt.*;
+import java.util.Map;
+
+public class GeoJSONReader {
+
+ /**
+ * Create a VectorLayer from GeoJSON feature collection
+ * @param features The feature collection
+ * @return VectorLayer object
+ */
+ public static VectorLayer read(FeatureCollection features) {
+ Shape shape = GeoJSONUtil.toShape(features.getFeature(0).getGeometry());
+ VectorLayer layer = new VectorLayer(shape.getShapeType());
+ String fieldName = "title";
+ layer.editAddField(fieldName, DataType.STRING);
+ LegendScheme ls = new LegendScheme(shape.getShapeType());
+ ls.setLegendType(LegendType.UNIQUE_VALUE);
+ ls.setFieldName(fieldName);
+ for (int i = 0; i < features.getNumFeatures(); i++) {
+ Feature feature = features.getFeature(i);
+ Map properties = feature.getProperties();
+ String titleValue = (String) properties.get("title");
+ PolygonBreak cb = new PolygonBreak();
+ cb.setStartValue(titleValue);
+ cb.setCaption(titleValue);
+ Color color = ColorUtil.parseToColor((String) properties.get("fill"));
+ float alpha = Float.parseFloat(properties.get("fill-opacity").toString());
+ color = ColorUtil.getColor(color, alpha);
+ cb.setColor(color);
+ color = ColorUtil.parseToColor((String) properties.get("stroke"));
+ alpha = Float.parseFloat(properties.get("stroke-opacity").toString());
+ color = ColorUtil.getColor(color, alpha);
+ cb.setOutlineColor(color);
+ float lineWidth = Float.parseFloat(properties.get("stroke-width").toString());
+ cb.setOutlineSize(lineWidth);
+ ls.addLegendBreak(cb);
+ Geometry geometry = feature.getGeometry();
+ if (geometry != null) {
+ try {
+ int idx = layer.getShapeNum();
+ layer.editInsertShape(GeoJSONUtil.toShape(geometry), idx);
+ layer.editCellValue(fieldName, idx, titleValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ layer.setLegendScheme(ls);
+
+ return layer;
+ }
+
+ /**
+ * Create a VectorLayer from GeoJSON string
+ * @param json The GeoJSON string
+ * @return VectorLayer object
+ */
+ public static VectorLayer read(String json) {
+ FeatureCollection features = (FeatureCollection) GeoJSONFactory.create(json);
+
+ return read(features);
+ }
+
+}
diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONWriter.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONWriter.java
new file mode 100644
index 00000000..92fb2c49
--- /dev/null
+++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/io/GeoJSONWriter.java
@@ -0,0 +1,63 @@
+package org.meteoinfo.geo.io;
+
+import org.meteoinfo.common.colors.ColorUtil;
+import org.meteoinfo.geo.layer.VectorLayer;
+import org.meteoinfo.geometry.io.geojson.Feature;
+import org.meteoinfo.geometry.io.geojson.FeatureCollection;
+import org.meteoinfo.geometry.io.geojson.GeoJSONUtil;
+import org.meteoinfo.geometry.io.geojson.Geometry;
+import org.meteoinfo.geometry.legend.*;
+import org.meteoinfo.geometry.shape.Shape;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GeoJSONWriter {
+
+ /**
+ * Write a vector layer to GeoJSON feature collection
+ *
+ * @param layer The vector layer
+ * @return GeoJSON feature collection
+ */
+ public static FeatureCollection write(VectorLayer layer) {
+ Feature[] features = new Feature[layer.getShapeNum()];
+ LegendScheme ls = layer.getLegendScheme();
+ for (int i = 0; i < layer.getShapeNum(); i++) {
+ Shape shape = layer.getShape(i);
+ Geometry geometry = GeoJSONUtil.fromShape(shape);
+ Map properties = new HashMap<>();
+ ColorBreak cb = ls.getLegendBreak(shape.getLegendIndex());
+ switch (cb.getBreakType()) {
+ case POINT_BREAK:
+ PointBreak pointBreak = (PointBreak) cb;
+ properties.put("marker-size", "medium");
+ properties.put("marker-color", ColorUtil.toHex(pointBreak.getColor()));
+ break;
+ case POLYLINE_BREAK:
+ PolylineBreak polylineBreak = (PolylineBreak) cb;
+ properties.put("stroke", ColorUtil.toHex(polylineBreak.getColor()));
+ properties.put("stroke-opacity", polylineBreak.getColor().getAlpha() / 255.f);
+ properties.put("stroke-width", polylineBreak.getWidth());
+ break;
+ case POLYGON_BREAK:
+ PolygonBreak polygonBreak = (PolygonBreak) cb;
+ properties.put("fill", ColorUtil.toHex(cb.getColor()));
+ properties.put("fill-opacity", cb.getColor().getAlpha() / 255.f);
+ if (polygonBreak.isDrawOutline()) {
+ properties.put("stroke", ColorUtil.toHex(polygonBreak.getOutlineColor()));
+ properties.put("stroke-opacity", polygonBreak.getOutlineColor().getAlpha() / 255.f);
+ properties.put("stroke-width", polygonBreak.getOutlineSize());
+ } else {
+ properties.put("stroke-opacity", 0);
+ }
+ break;
+ }
+ properties.put("title", cb.getCaption());
+ features[i] = new Feature(geometry, properties);
+ }
+
+ return new FeatureCollection(features);
+ }
+
+}
diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layer/VectorLayer.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layer/VectorLayer.java
index e6fb13a9..01940014 100644
--- a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layer/VectorLayer.java
+++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layer/VectorLayer.java
@@ -1412,6 +1412,17 @@ public class VectorLayer extends MapLayer {
}
}
+ /**
+ * Edit: Remove a shape by index
+ * @param idx The index
+ */
+ public void editRemoveShape(int idx) {
+ if (idx >= 0 && idx < this.getShapeNum() - 1) {
+ this._shapeList.remove(idx);
+ this._attributeTable.getTable().removeRow(idx);
+ }
+ }
+
private void updateLayerExtent(Shape aShape) {
if (this.getShapeNum() == 1) {
this.setExtent((Extent) aShape.getExtent().clone());
diff --git a/meteoinfo-geometry/pom.xml b/meteoinfo-geometry/pom.xml
index dbce8ef6..c8945ff0 100644
--- a/meteoinfo-geometry/pom.xml
+++ b/meteoinfo-geometry/pom.xml
@@ -37,6 +37,16 @@
jts-core
1.19.0
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.4.2
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.13.4
+
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Feature.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Feature.java
new file mode 100644
index 00000000..e62daed8
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Feature.java
@@ -0,0 +1,46 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonPropertyOrder({"type", "id", "geometry", "properties"})
+public class Feature extends GeoJSON {
+ @JsonInclude(Include.NON_EMPTY)
+ private final Object id;
+ private final Geometry geometry;
+ private final Map properties;
+
+ public Feature(
+ @JsonProperty("geometry") Geometry geometry,
+ @JsonProperty("properties") Map properties) {
+ this(null, geometry, properties);
+ }
+
+ @JsonCreator
+ public Feature(
+ @JsonProperty("id") Object id,
+ @JsonProperty("geometry") Geometry geometry,
+ @JsonProperty("properties") Map properties) {
+ super();
+ this.id = id;
+ this.geometry = geometry;
+ this.properties = properties;
+ }
+
+ public Object getId() {
+ return id;
+ }
+
+ public Geometry getGeometry() {
+ return geometry;
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/FeatureCollection.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/FeatureCollection.java
new file mode 100644
index 00000000..e2c16aba
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/FeatureCollection.java
@@ -0,0 +1,41 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonPropertyOrder({"type", "features"})
+public class FeatureCollection extends GeoJSON {
+ private final Feature[] features;
+
+ @JsonCreator
+ public FeatureCollection(@JsonProperty("features") Feature[] features) {
+ super();
+ this.features = features;
+ }
+
+ /**
+ * Get features
+ * @return Features
+ */
+ public Feature[] getFeatures() {
+ return features;
+ }
+
+ /**
+ * Get number of features
+ * @return Number of features
+ */
+ public int getNumFeatures() {
+ return features.length;
+ }
+
+ /**
+ * Get a feature by index
+ * @param index The index
+ * @return The feature
+ */
+ public Feature getFeature(int index) {
+ return features[index];
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSON.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSON.java
new file mode 100644
index 00000000..25dae325
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSON.java
@@ -0,0 +1,58 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+@JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.EXISTING_PROPERTY,
+ property = "type"
+)
+@JsonSubTypes( {
+ @JsonSubTypes.Type(value=Point.class, name="Point" ),
+ @JsonSubTypes.Type(value=LineString.class, name="LineString" ),
+ @JsonSubTypes.Type(value=Polygon.class, name="Polygon" ),
+ @JsonSubTypes.Type(value=MultiPoint.class, name="MultiPoint" ),
+ @JsonSubTypes.Type(value=MultiLineString.class, name="MultiLineString" ),
+ @JsonSubTypes.Type(value=MultiPolygon.class, name="MultiPolygon" ),
+ @JsonSubTypes.Type(value=Feature.class, name="Feature" ),
+ @JsonSubTypes.Type(value=FeatureCollection.class, name="FeatureCollection" ),
+ @JsonSubTypes.Type(value=GeometryCollection.class, name="GeometryCollection" )
+})
+public abstract class GeoJSON {
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ @JsonProperty("type")
+ private String type;
+
+ @JsonCreator
+ public GeoJSON() {
+ setType(getClass().getSimpleName());
+ }
+
+ public String toString() {
+ try {
+ return mapper.writeValueAsString(this);
+ } catch (JsonGenerationException e) {
+ return "Unhandled exception occured when serializing this instance";
+ } catch (JsonMappingException e) {
+ return "Unhandled exception occured when serializing this instance";
+ } catch (IOException e) {
+ return "Unhandled exception occured when serializing this instance";
+ }
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONFactory.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONFactory.java
new file mode 100644
index 00000000..ed42262b
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONFactory.java
@@ -0,0 +1,65 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.MapType;
+
+public class GeoJSONFactory {
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ public static GeoJSON create(String json) {
+ try {
+ JsonNode node = mapper.readTree(json);
+ String type = node.get("type").asText();
+ if (type.equals("FeatureCollection"))
+ return readFeatureCollection(node);
+ else if (type.equals("Feature"))
+ return readFeature(node);
+ else
+ return readGeometry(node, type);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static FeatureCollection readFeatureCollection(JsonNode node)
+ throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
+ Iterator it = node.get("features").iterator();
+ List features = new ArrayList<>();
+ while (it.hasNext())
+ features.add(readFeature(it.next()));
+ return new FeatureCollection(features.toArray(new Feature[features.size()]));
+ }
+
+ private static Feature readFeature(JsonNode node)
+ throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
+ JsonNode geometryNode = node.get("geometry");
+ MapType javaType = mapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
+ JsonNode id = node.get("id");
+ Map properties = mapper.readValue(node.get("properties").traverse(), javaType);
+ Geometry geometry = readGeometry(geometryNode);
+ return new Feature(id, geometry, properties);
+ }
+
+ private static Geometry readGeometry(JsonNode node)
+ throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
+ if (node != null && !node.isNull())
+ return readGeometry(node, node.get("type").asText());
+ else
+ return null;
+ }
+
+ private static Geometry readGeometry(JsonNode node, String type)
+ throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
+ return (Geometry) mapper.readValue(node.traverse(), Class.forName("org.meteoinfo.geometry.io.geojson." + type));
+ }
+
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONUtil.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONUtil.java
new file mode 100644
index 00000000..cfb4fb00
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeoJSONUtil.java
@@ -0,0 +1,341 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import org.meteoinfo.common.PointD;
+import org.meteoinfo.geometry.shape.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GeoJSONUtil {
+
+ /**
+ * Convert GeoJSON geometry to shape
+ *
+ * @param geometry The geometry
+ * @return Shape
+ */
+ public static Shape toShape(Geometry geometry) {
+ if (geometry instanceof Point) {
+ return toShape((Point) geometry);
+ } else if (geometry instanceof LineString) {
+ return toShape((LineString) geometry);
+ } else if (geometry instanceof MultiLineString) {
+ return toShape((MultiLineString) geometry);
+ } else if (geometry instanceof Polygon) {
+ return toShape((Polygon) geometry);
+ } else if (geometry instanceof MultiPolygon) {
+ return toShape((MultiPolygon) geometry);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Convert shape to GeoJSON geometry
+ *
+ * @param shape The shape
+ * @return Geometry
+ */
+ public static Geometry fromShape(Shape shape) {
+ if (shape instanceof PointShape) {
+ return fromShape((PointShape) shape);
+ } else if (shape instanceof PolylineShape) {
+ return fromShape((PolylineShape) shape);
+ } else if (shape instanceof PolygonShape) {
+ return fromShape((PolygonShape) shape);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Convert PointShape to GeoJSON Point
+ *
+ * @param pointShape The PointShape object
+ * @return GeoJSON Point object
+ */
+ public static Point fromShape(PointShape pointShape) {
+ PointD p = pointShape.getPoint();
+
+ return new Point(p.toArray());
+ }
+
+ /**
+ * Convert GeoJSON Point to PointShape
+ *
+ * @param point The GeoJSON Point object
+ * @return PointShape object
+ */
+ public static PointShape toShape(Point point) {
+ double[] coordinates = point.getCoordinates();
+ if (coordinates.length == 2) {
+ return new PointShape(new PointD(coordinates[0], coordinates[1]));
+ } else {
+ return new PointZShape(new PointZ(coordinates[0], coordinates[1], coordinates[2]));
+ }
+ }
+
+ /**
+ * Convert PolylineShape to GeoJSON LineString or MultiLineString
+ *
+ * @param polylineShape The PolylineShape object
+ * @return GeoJSON LineString or MultiLineString object
+ */
+ public static Geometry fromShape(PolylineShape polylineShape) {
+ if (polylineShape.isMultiLine()) {
+ int lineNum = polylineShape.getPartNum();
+ double[][][] coordinates = new double[lineNum][][];
+ int cNum = polylineShape.getShapeType() == ShapeTypes.POLYLINE ? 2 : 3;
+ for (int j = 0; j < lineNum; j++) {
+ Polyline polyline = polylineShape.getPolylines().get(j);
+ int pNum = polyline.getPointList().size();
+ double[][] matrix = new double[pNum][cNum];
+ for (int i = 0; i < pNum; i++) {
+ matrix[i] = polyline.getPointList().get(i).toArray();
+ }
+ coordinates[j] = matrix;
+ }
+
+ return new MultiLineString(coordinates);
+ } else {
+ int cNum = polylineShape.getShapeType() == ShapeTypes.POLYLINE ? 2 : 3;
+ double[][] coordinates = new double[polylineShape.getPointNum()][cNum];
+ for (int i = 0; i < polylineShape.getPointNum(); i++) {
+ coordinates[i] = polylineShape.getPoints().get(i).toArray();
+ }
+
+ return new LineString(coordinates);
+ }
+ }
+
+ /**
+ * Convert GeoJSON LineString to PolylineShape
+ *
+ * @param lineString The GeoJSON LineString object
+ * @return PolylineShape object
+ */
+ public static PolylineShape toShape(LineString lineString) {
+ double[][] coordinates = lineString.getCoordinates();
+ int pNum = coordinates.length;
+ if (coordinates[0].length == 2) {
+ List points = new ArrayList<>();
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointD(coordinates[i][0], coordinates[i][1]));
+ }
+
+ return new PolylineShape(points);
+ } else {
+ List points = new ArrayList<>();
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointZ(coordinates[i][0], coordinates[i][1], coordinates[i][2]));
+ }
+
+ return new PolylineZShape(points);
+ }
+ }
+
+ /**
+ * Convert GeoJSON LineString to PolylineShape
+ *
+ * @param lineString The GeoJSON LineString object
+ * @return PolylineShape object
+ */
+ public static PolylineShape toShape(MultiLineString lineString) {
+ double[][][] coordinates = lineString.getCoordinates();
+ int lineNum = coordinates.length;
+ int cNum = coordinates[0][0].length;
+ if (cNum == 2) {
+ PolylineShape polylineShape = new PolylineShape();
+ polylineShape.setPartNum(lineNum);
+ polylineShape.parts = new int[lineNum];
+ List points = new ArrayList<>();
+ for (int j = 0; j < lineNum; j++) {
+ int pNum = coordinates[j].length;
+ polylineShape.parts[j] = pNum;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointD(coordinates[j][i][0], coordinates[j][i][1]));
+ }
+ }
+ polylineShape.setPoints(points);
+
+ return polylineShape;
+ } else {
+ PolylineZShape polylineZShape = new PolylineZShape();
+ polylineZShape.setPartNum(lineNum);
+ polylineZShape.parts = new int[lineNum];
+ List points = new ArrayList<>();
+ for (int j = 0; j < lineNum; j++) {
+ int pNum = coordinates[j].length;
+ polylineZShape.parts[j] = pNum;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointZ(coordinates[j][i][0], coordinates[j][i][1], coordinates[j][i][2]));
+ }
+ }
+ polylineZShape.setPoints(points);
+
+ return polylineZShape;
+ }
+ }
+
+ /**
+ * Convert PolygonShape to GeoJSON Polygon or MultiPolygon
+ *
+ * @param polygonShape The PolygonShape object
+ * @return GeoJSON Polygon or MultiPolygon object
+ */
+ public static Geometry fromShape(PolygonShape polygonShape) {
+ int cNum = polygonShape.getShapeType() == ShapeTypes.POLYGON ? 2 : 3;
+ if (polygonShape.isMultiPolygon()) {
+ int polygonNum = polygonShape.getPolygons().size();
+ double[][][][] coordinates = new double[polygonNum][][][];
+ for (int k = 0; k < polygonNum; k++) {
+ org.meteoinfo.geometry.shape.Polygon sPolygon = polygonShape.getPolygon(k);
+ int ringNumber = sPolygon.getRingNumber();
+ double[][][] a3d = new double[ringNumber][][];
+ int pNum = sPolygon.getOutLine().size();
+ double[][] matrix = new double[pNum][cNum];
+ for (int i = 0; i < pNum; i++) {
+ matrix[i] = sPolygon.getOutLine().get(i).toArray();
+ }
+ a3d[0] = matrix;
+ if (sPolygon.hasHole()) {
+ for (int j = 0; j < sPolygon.getHoleLineNumber(); j++) {
+ pNum = sPolygon.getHoleLine(j).size();
+ matrix = new double[pNum][cNum];
+ for (int i = 0; i < sPolygon.getHoleLine(j).size(); i++) {
+ matrix[i] = sPolygon.getHoleLine(j).get(i).toArray();
+ }
+ a3d[j + 1] = matrix;
+ }
+ }
+ coordinates[k] = a3d;
+ }
+
+ return new MultiPolygon(coordinates);
+ } else {
+ org.meteoinfo.geometry.shape.Polygon sPolygon = polygonShape.getPolygon(0);
+ int ringNum = sPolygon.getRingNumber();
+ double[][][] coordinates = new double[ringNum][][];
+ int pNum = sPolygon.getOutLine().size();
+ double[][] matrix = new double[pNum][cNum];
+ for (int i = 0; i < pNum; i++) {
+ matrix[i] = sPolygon.getOutLine().get(i).toArray();
+ }
+ coordinates[0] = matrix;
+ if (sPolygon.hasHole()) {
+ for (int j = 0; j < sPolygon.getHoleLineNumber(); j++) {
+ pNum = sPolygon.getHoleLine(j).size();
+ matrix = new double[pNum][cNum];
+ for (int i = 0; i < sPolygon.getHoleLine(j).size(); i++) {
+ matrix[i] = sPolygon.getHoleLine(j).get(i).toArray();
+ }
+ coordinates[j + 1] = matrix;
+ }
+ }
+
+ return new Polygon(coordinates);
+ }
+ }
+
+ /**
+ * Convert GeoJSON Polygon to PolygonShape
+ *
+ * @param polygon The GeoJSON Polygon object
+ * @return PolygonShape object
+ */
+ public static PolygonShape toShape(Polygon polygon) {
+ double[][][] coordinates = polygon.getCoordinates();
+ int ringNum = coordinates.length;
+ int cNum = coordinates[0][0].length;
+ if (cNum == 2) {
+ PolygonShape polygonShape = new PolygonShape();
+ polygonShape.setPartNum(ringNum);
+ polygonShape.parts = new int[ringNum];
+ List points = new ArrayList<>();
+ for (int j = 0; j < ringNum; j++) {
+ int pNum = coordinates[j].length;
+ polygonShape.parts[j] = pNum;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointD(coordinates[j][i][0], coordinates[j][i][1]));
+ }
+ }
+ polygonShape.setPoints(points);
+
+ return polygonShape;
+ } else {
+ PolygonZShape polygonZShape = new PolygonZShape();
+ polygonZShape.setPartNum(ringNum);
+ polygonZShape.parts = new int[ringNum];
+ List points = new ArrayList<>();
+ for (int j = 0; j < ringNum; j++) {
+ int pNum = coordinates[j].length;
+ polygonZShape.parts[j] = pNum;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointZ(coordinates[j][i][0], coordinates[j][i][1], coordinates[j][i][2]));
+ }
+ }
+ polygonZShape.setPoints(points);
+
+ return polygonZShape;
+ }
+ }
+
+ /**
+ * Convert GeoJSON MultiPolygon to PolygonShape
+ *
+ * @param multiPolygon The GeoJSON MultiPolygon object
+ * @return PolygonShape object
+ */
+ public static PolygonShape toShape(MultiPolygon multiPolygon) {
+ double[][][][] coordinates = multiPolygon.getCoordinates();
+ int polygonNum = coordinates.length;
+ int cNum = coordinates[0][0][0].length;
+ if (cNum == 2) {
+ List polygons = new ArrayList<>();
+ for (int k = 0; k < polygonNum; k++) {
+ int ringNum = coordinates[k].length;
+ org.meteoinfo.geometry.shape.Polygon polygon = new org.meteoinfo.geometry.shape.Polygon();
+ for (int j = 0; j < ringNum; j++) {
+ List points = new ArrayList<>();
+ int pNum = coordinates[k][j].length;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointD(coordinates[k][j][i][0], coordinates[k][j][i][1]));
+ }
+ if (j == 0) {
+ polygon.setOutLine(points);
+ } else {
+ polygon.addHole(points);
+ }
+ }
+ polygons.add(polygon);
+ }
+ PolygonShape polygonShape = new PolygonShape();
+ polygonShape.setPolygons(polygons);
+
+ return polygonShape;
+ } else {
+ List polygons = new ArrayList<>();
+ for (int k = 0; k < polygonNum; k++) {
+ int ringNum = coordinates[k].length;
+ org.meteoinfo.geometry.shape.Polygon polygon = new org.meteoinfo.geometry.shape.Polygon();
+ for (int j = 0; j < ringNum; j++) {
+ List points = new ArrayList<>();
+ int pNum = coordinates[k][j].length;
+ for (int i = 0; i < pNum; i++) {
+ points.add(new PointZ(coordinates[k][j][i][0], coordinates[k][j][i][1],
+ coordinates[k][j][i][2]));
+ }
+ if (j == 0) {
+ polygon.setOutLine(points);
+ } else {
+ polygon.addHole(points);
+ }
+ }
+ polygons.add(polygon);
+ }
+ PolygonZShape polygonZShape = new PolygonZShape();
+ polygonZShape.setPolygons(polygons);
+
+ return polygonZShape;
+ }
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Geometry.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Geometry.java
new file mode 100644
index 00000000..0974d4ee
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Geometry.java
@@ -0,0 +1,33 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.EXISTING_PROPERTY,
+ property = "type"
+)
+@JsonSubTypes( {
+ @JsonSubTypes.Type(value=Point.class, name="Point" ),
+ @JsonSubTypes.Type(value=LineString.class, name="LineString" ),
+ @JsonSubTypes.Type(value=Polygon.class, name="Polygon" ),
+ @JsonSubTypes.Type(value=MultiPoint.class, name="MultiPoint" ),
+ @JsonSubTypes.Type(value=MultiLineString.class, name="MultiLineString" ),
+ @JsonSubTypes.Type(value=MultiPolygon.class, name="MultiPolygon" ),
+ @JsonSubTypes.Type(value=Feature.class, name="Feature" ),
+ @JsonSubTypes.Type(value=FeatureCollection.class, name="FeatureCollection" ),
+ @JsonSubTypes.Type(value=GeometryCollection.class, name="GeometryCollection" )
+} )
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({"type", "coordinates", "bbox"})
+public abstract class Geometry extends GeoJSON {
+ @JsonCreator
+ public Geometry() {
+ super();
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeometryCollection.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeometryCollection.java
new file mode 100644
index 00000000..7d534a30
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/GeometryCollection.java
@@ -0,0 +1,20 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonPropertyOrder({"type", "geometries"})
+public class GeometryCollection extends Geometry {
+ private final Geometry[] geometries;
+
+ @JsonCreator
+ public GeometryCollection(@JsonProperty("geometries") Geometry[] geometries) {
+ super();
+ this.geometries = geometries;
+ }
+
+ public Geometry[] getGeometries() {
+ return geometries;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/LineString.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/LineString.java
new file mode 100644
index 00000000..55e921f7
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/LineString.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class LineString extends Geometry {
+ private final double[][] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public LineString(@JsonProperty("coordinates") double [][] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[][] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiLineString.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiLineString.java
new file mode 100644
index 00000000..ce7923b9
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiLineString.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class MultiLineString extends Geometry {
+ private final double[][][] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public MultiLineString(@JsonProperty("coordinates") double [][][] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[][][] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPoint.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPoint.java
new file mode 100644
index 00000000..e3ee5925
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPoint.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class MultiPoint extends Geometry {
+ private final double[][] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public MultiPoint(@JsonProperty("coordinates") double [][] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[][] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPolygon.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPolygon.java
new file mode 100644
index 00000000..b77ca7c1
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/MultiPolygon.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class MultiPolygon extends Geometry {
+ private final double[][][][] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public MultiPolygon(@JsonProperty("coordinates") double [][][][] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[][][][] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Point.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Point.java
new file mode 100644
index 00000000..f5920be0
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Point.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class Point extends Geometry {
+ private final double[] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public Point(@JsonProperty("coordinates") double [] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Polygon.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Polygon.java
new file mode 100644
index 00000000..3fcc0720
--- /dev/null
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/io/geojson/Polygon.java
@@ -0,0 +1,27 @@
+package org.meteoinfo.geometry.io.geojson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class Polygon extends Geometry {
+ private final double[][][] coordinates;
+ private final double[] bbox;
+
+ @JsonCreator
+ public Polygon(@JsonProperty("coordinates") double [][][] coordinates) {
+ super();
+ this.coordinates = coordinates;
+ this.bbox = null;
+ }
+
+ public double[][][] getCoordinates() {
+ return coordinates;
+ }
+
+ public double[] getBbox() {
+ return bbox;
+ }
+}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZ.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZ.java
index b216660f..202455c2 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZ.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZ.java
@@ -94,6 +94,7 @@ public class PointZ extends PointD implements Cloneable{
* To double array
* @return Double array
*/
+ @Override
public double[] toArray() {
return new double[]{X, Y, Z};
}
@@ -102,6 +103,7 @@ public class PointZ extends PointD implements Cloneable{
* To float array
* @return Float array
*/
+ @Override
public float[] toFloatArray() {
return new float[]{(float) X, (float) Y, (float) Z};
}
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZShape.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZShape.java
index 194bf9aa..5ed75b19 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZShape.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PointZShape.java
@@ -38,6 +38,15 @@ public class PointZShape extends PointShape {
this.point = new PointZ();
this.updateExtent((PointZ)this.point);
}
+
+ /**
+ * Constructor
+ * @param pointZ The PointZ object
+ */
+ public PointZShape(PointZ pointZ) {
+ this.point = pointZ;
+ this.updateExtent(pointZ);
+ }
/**
* Constructor
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/Polygon.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/Polygon.java
index 1050cb8c..47e9f38d 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/Polygon.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/Polygon.java
@@ -77,19 +77,6 @@ public class Polygon {
return this._holeLines;
}
- /**
- * Get hole lines
- *
- * @return hole lines
- */
- public List> getHoleLines_bak() {
- List> hlines = new ArrayList<>();
- for (List extends PointD> hline : _holeLines){
- hlines.add((List)hline);
- }
- return hlines;
- }
-
/**
* Get a hole line
* @param idx Index
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolygonShape.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolygonShape.java
index b4b2d019..0ae8d660 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolygonShape.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolygonShape.java
@@ -150,6 +150,14 @@ public class PolygonShape extends Shape implements Cloneable {
return ShapeTypes.POLYGON;
}
+ /**
+ * Get is multi polygon or not
+ * @return Multi polygon or not
+ */
+ public boolean isMultiPolygon() {
+ return this._numParts > 1;
+ }
+
/**
* To geometry method
*
@@ -279,6 +287,15 @@ public class PolygonShape extends Shape implements Cloneable {
return _polygons;
}
+ /**
+ * Get a polygon
+ * @param index The polygon index
+ * @return The polygon
+ */
+ public Polygon getPolygon(int index) {
+ return _polygons.get(index);
+ }
+
/**
* Set polygons
*
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineShape.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineShape.java
index 9204e95c..72c835b5 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineShape.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineShape.java
@@ -58,6 +58,14 @@ public class PolylineShape extends Shape implements Cloneable {
_polylines = new ArrayList<>();
}
+ /**
+ * Constructor
+ * @param points Point list
+ */
+ public PolylineShape(List points) {
+ this.setPoints(points);
+ }
+
/**
* Constructor
*
@@ -109,6 +117,14 @@ public class PolylineShape extends Shape implements Cloneable {
return ShapeTypes.POLYLINE;
}
+ /**
+ * Get is multi line or not
+ * @return Multi line or not
+ */
+ public boolean isMultiLine() {
+ return this._numParts > 1;
+ }
+
/**
* To geometry method
*
diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineZShape.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineZShape.java
index 559a6560..56c48929 100644
--- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineZShape.java
+++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/PolylineZShape.java
@@ -41,6 +41,14 @@ public class PolylineZShape extends PolylineShape {
public PolylineZShape() {
super();
}
+
+ /**
+ * Constructor
+ * @param points Points
+ */
+ public PolylineZShape(List points) {
+ this.setPoints(points);
+ }
/**
* Constructor
diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml
index e8cf14c4..ab03809d 100644
--- a/meteoinfo-lab/milconfig.xml
+++ b/meteoinfo-lab/milconfig.xml
@@ -1,32 +1,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
@@ -34,5 +34,5 @@
-
+
diff --git a/meteoinfo-lab/pylib/mipylib/geolib/milayer$py.class b/meteoinfo-lab/pylib/mipylib/geolib/milayer$py.class
index 6b5d57ab..720e113d 100644
Binary files a/meteoinfo-lab/pylib/mipylib/geolib/milayer$py.class and b/meteoinfo-lab/pylib/mipylib/geolib/milayer$py.class differ
diff --git a/meteoinfo-lab/pylib/mipylib/geolib/milayer.py b/meteoinfo-lab/pylib/mipylib/geolib/milayer.py
index 5a782ecd..25459971 100644
--- a/meteoinfo-lab/pylib/mipylib/geolib/milayer.py
+++ b/meteoinfo-lab/pylib/mipylib/geolib/milayer.py
@@ -17,6 +17,7 @@ from org.meteoinfo.projection import ProjectionUtil, KnownCoordinateSystems
from org.meteoinfo.geometry.shape import PolygonShape, ShapeTypes
from org.meteoinfo.geo.analysis import GeometryUtil
from org.meteoinfo.geo.util import GeoProjectionUtil
+from org.meteoinfo.geo.io import GeoJSONReader, GeoJSONWriter
class MILayer(object):
@@ -277,6 +278,14 @@ class MILayer(object):
for shape, field in zip(shapes, fields):
self._layer.editAddShape(shape, field)
+ def del_shape(self, shape):
+ """
+ Delete a shape.
+
+ :param shape: (*Shape or int*) The shape or shape index to be deleted.
+ """
+ self._layer.editRemoveShape(shape)
+
def copy(self):
"""
Copy the layer.
@@ -547,7 +556,7 @@ class MILayer(object):
else:
self._layer.saveFile(fn, encoding)
- def savekml(self, fn):
+ def save_kml(self, fn):
"""
Save layer as KML file.
@@ -555,7 +564,7 @@ class MILayer(object):
"""
self._layer.saveAsKMLFile(fn)
- def savebil(self, fn, proj=None):
+ def save_bil(self, fn, proj=None):
"""
Save layer as bil file.
@@ -567,6 +576,27 @@ class MILayer(object):
else:
self._layer.saveFile(fn, proj)
+ def save_geojson(self, fn):
+ """
+ Save layer as GeoJSON file.
+
+ :param fn: (*str*) GeoJSON file name.
+ """
+ features = GeoJSONWriter.write(self._layer)
+ with open(fn, 'w') as f:
+ f.write("{\n")
+ f.write(""""type": "FeatureCollection",\n""")
+ f.write(""""features": [\n""")
+ for i in range(features.getNumFeatures()):
+ feature = features.getFeature(i)
+ f.write(feature.toString())
+ if i < features.getNumFeatures() - 1:
+ f.write(",\n")
+ else:
+ f.write("\n")
+ f.write("]\n")
+ f.write("}")
+
class MIXYListData():
def __init__(self, data=None):
diff --git a/pom.xml b/pom.xml
index f06df31d..ca78d2a9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,7 +34,7 @@
UTF-8
1.8
- 3.7.8
+ 3.7.9
8
8
8