--- /dev/null
+package org.argeo.app.geo;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.geotools.data.DataUtilities;
+import org.geotools.data.DefaultTransaction;
+import org.geotools.data.Transaction;
+import org.geotools.data.collection.ListFeatureCollection;
+import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
+import org.geotools.data.simple.SimpleFeatureCollection;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.data.simple.SimpleFeatureStore;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.geotools.swing.data.JFileDataStoreChooser;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.Point;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
+public class GeoToolsTest {
+ public GeoToolsTest() {
+
+ }
+
+ public void init() {
+ try {
+ main(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void destroy() {
+
+ }
+
+ public static void main(String[] args) throws Exception {
+ final SimpleFeatureType TYPE = DataUtilities.createType("Location", "the_geom:Point:srid=4326," + // <- the
+ // geometry
+ // attribute:
+ // Point
+ // type
+ "name:String," + // <- a String attribute
+ "number:Integer" // a number attribute
+ );
+ final SimpleFeatureType TYPE_HULL = DataUtilities.createType("Hull", "the_geom:MultiPolygon:srid=4326");
+ System.out.println("TYPE:" + TYPE);
+
+ /*
+ * A list to collect features as we create them.
+ */
+ List<SimpleFeature> features = new ArrayList<>();
+ List<Coordinate> coordinates = new ArrayList<>();
+
+ /*
+ * GeometryFactory will be used to create the geometry attribute of each
+ * feature, using a Point object for the location.
+ */
+ GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
+
+ SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
+
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(GeoToolsTest.class.getResourceAsStream("/org/djapps/on/apaf/locations.csv")))) {
+ /* First line of the data file is the header */
+ String line = reader.readLine();
+ System.out.println("Header: " + line);
+
+ for (line = reader.readLine(); line != null; line = reader.readLine()) {
+ if (line.trim().length() > 0) { // skip blank lines
+ String[] tokens = line.split("\\,");
+
+ double latitude = Double.parseDouble(tokens[0]);
+ double longitude = Double.parseDouble(tokens[1]);
+ String name = tokens[2].trim();
+ int number = Integer.parseInt(tokens[3].trim());
+
+ /* Longitude (= x coord) first ! */
+ Coordinate coordinate = new Coordinate(longitude, latitude);
+ coordinates.add(coordinate);
+ Point point = geometryFactory.createPoint(coordinate);
+
+ featureBuilder.add(point);
+ featureBuilder.add(name);
+ featureBuilder.add(number);
+ SimpleFeature feature = featureBuilder.buildFeature(null);
+ features.add(feature);
+ }
+ }
+ }
+
+ LineString lineString = geometryFactory
+ .createLineString(coordinates.toArray(new Coordinate[coordinates.size()]));
+ Geometry convexHull = lineString.convexHull();
+ System.out.println(convexHull.toText());
+ SimpleFeatureBuilder hullFeatureBuilder = new SimpleFeatureBuilder(TYPE_HULL);
+ hullFeatureBuilder.add(convexHull);
+ SimpleFeature hull = hullFeatureBuilder.buildFeature(null);
+
+ /*
+ * Get an output file name and create the new shapefile
+ */
+ File newFile = getNewShapeFile();
+
+ ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
+
+ Map<String, Serializable> params = new HashMap<>();
+ params.put("url", newFile.toURI().toURL());
+ params.put("create spatial index", Boolean.TRUE);
+
+ ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
+
+ /*
+ * TYPE is used as a template to describe the file contents
+ */
+ newDataStore.createSchema(TYPE_HULL);
+
+ /*
+ * Write the features to the shapefile
+ */
+ Transaction transaction = new DefaultTransaction("create");
+
+ String typeName = newDataStore.getTypeNames()[0];
+ SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
+ SimpleFeatureType SHAPE_TYPE = featureSource.getSchema();
+ /*
+ * The Shapefile format has a couple limitations: - "the_geom" is always first,
+ * and used for the geometry attribute name - "the_geom" must be of type Point,
+ * MultiPoint, MuiltiLineString, MultiPolygon - Attribute names are limited in
+ * length - Not all data types are supported (example Timestamp represented as
+ * Date)
+ *
+ * Each data store has different limitations so check the resulting
+ * SimpleFeatureType.
+ */
+ System.out.println("SHAPE:" + SHAPE_TYPE);
+
+ if (featureSource instanceof SimpleFeatureStore) {
+ SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
+ /*
+ * SimpleFeatureStore has a method to add features from a
+ * SimpleFeatureCollection object, so we use the ListFeatureCollection class to
+ * wrap our list of features.
+ */
+ SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, Collections.singletonList(hull));
+ featureStore.setTransaction(transaction);
+ try {
+ featureStore.addFeatures(collection);
+ transaction.commit();
+ } catch (Exception problem) {
+ problem.printStackTrace();
+ transaction.rollback();
+ } finally {
+ transaction.close();
+ }
+ } else {
+ System.out.println(typeName + " does not support read/write access");
+ }
+// if (featureSource instanceof SimpleFeatureStore) {
+// SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
+// /*
+// * SimpleFeatureStore has a method to add features from a
+// * SimpleFeatureCollection object, so we use the ListFeatureCollection class to
+// * wrap our list of features.
+// */
+// SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
+// featureStore.setTransaction(transaction);
+// try {
+// featureStore.addFeatures(collection);
+// transaction.commit();
+// } catch (Exception problem) {
+// problem.printStackTrace();
+// transaction.rollback();
+// } finally {
+// transaction.close();
+// }
+// } else {
+// System.out.println(typeName + " does not support read/write access");
+// }
+ }
+
+ /**
+ * Prompt the user for the name and path to use for the output shapefile
+ *
+ * @param csvFile the input csv file used to create a default shapefile name
+ * @return name and path for the shapefile as a new File object
+ */
+ private static File getNewShapeFile() {
+// String path = csvFile.getAbsolutePath();
+// String newPath = path.substring(0, path.length() - 4) + ".shp";
+
+ JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp");
+ chooser.setDialogTitle("Save shapefile");
+// chooser.setSelectedFile(new File(newPath));
+
+ int returnVal = chooser.showSaveDialog(null);
+
+ if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) {
+ // the user cancelled the dialog
+ System.exit(0);
+ }
+
+ File newFile = chooser.getSelectedFile();
+
+ return newFile;
+ }
+
+}
--- /dev/null
+package org.argeo.app.geo;
+
+import javax.measure.Quantity;
+import javax.measure.quantity.Area;
+
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.Polygon;
+import org.opengis.feature.simple.SimpleFeature;
+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 si.uom.SI;
+import tech.units.indriya.quantity.Quantities;
+
+/** Utilities around geographical format, mostly wrapping GeoTools patterns. */
+public class GeoUtils {
+
+ /** In square meters. */
+ public static Quantity<Area> calcArea(SimpleFeature feature) {
+ try {
+ Polygon p = (Polygon) feature.getDefaultGeometry();
+ Point centroid = p.getCentroid();
+ String code = "AUTO:42001," + centroid.getX() + "," + centroid.getY();
+ CoordinateReferenceSystem auto = CRS.decode(code);
+
+ MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
+
+ Polygon projed = (Polygon) JTS.transform(p, transform);
+ return Quantities.getQuantity(projed.getArea(), SI.SQUARE_METRE);
+ } catch (MismatchedDimensionException | FactoryException | TransformException e) {
+ throw new IllegalStateException("Cannot claculate area of feature");
+ }
+ }
+
+ /** Singleton. */
+ private GeoUtils() {
+ }
+}
--- /dev/null
+package org.argeo.app.geo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.geotools.data.DataUtilities;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Polygon;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/** Utilities around the GPX format. */
+public class GpxUtils {
+
+ public static SimpleFeature parseGpxToPolygon(InputStream in) {
+ try {
+ final SimpleFeatureType TYPE = DataUtilities.createType("Area", "the_geom:Polygon:srid=4326");
+ SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
+
+ GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
+ List<Coordinate> coordinates = new ArrayList<>();
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ Double[] startCoord = new Double[2];
+ SAXParser saxParser = factory.newSAXParser();
+
+ saxParser.parse(in, new DefaultHandler() {
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ if ("trkpt".equals(qName)) {
+ Double latitude = Double.parseDouble(attributes.getValue("lat"));
+ Double longitude = Double.parseDouble(attributes.getValue("lon"));
+ Coordinate coordinate = new Coordinate(longitude, latitude);
+ coordinates.add(coordinate);
+ }
+ }
+
+ });
+ // close the line string
+ coordinates.add(coordinates.get(0));
+
+ Polygon polygon = geometryFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()]));
+ featureBuilder.add(polygon);
+ SimpleFeature area = featureBuilder.buildFeature(null);
+ return area;
+ } catch (ParserConfigurationException | SAXException | IOException | SchemaException e) {
+ throw new RuntimeException("Cannot convert GPX", e);
+ }
+ }
+
+ /** Singleton. */
+ private GpxUtils() {
+ }
+}