() {
+ protected String doInBackground() throws Exception {
+ // For shapefiles with many features its nice to display a progress bar
+ final JProgressWindow progress = new JProgressWindow(null);
+ progress.setTitle("Validating feature geometry");
+
+ int numInvalid = validateFeatureGeometry(progress);
+ if (numInvalid == 0) {
+ return "All feature geometries are valid";
+ } else {
+ return "Invalid geometries: " + numInvalid;
+ }
+ }
+ protected void done() {
+ try {
+ Object result = get();
+ JOptionPane.showMessageDialog(null, result, "Geometry results",
+ JOptionPane.INFORMATION_MESSAGE);
+ } catch (Exception ignore) {
+ }
+ }
+ };
+ // This statement runs the validation method in a background thread
+ worker.execute();
+ }
+
+ private int validateFeatureGeometry(ProgressListener progress) throws Exception {
+ final SimpleFeatureCollection featureCollection = CRSLab.featureSource.getFeatures();
+
+ // Rather than use an iterator, create a FeatureVisitor to check each fature
+ class ValidationVisitor implements FeatureVisitor {
+ public int numInvalidGeometries = 0;
+ public void visit(Feature f) {
+ SimpleFeature feature = (SimpleFeature) f;
+ Geometry geom = (Geometry) feature.getDefaultGeometry();
+ if (geom != null && !geom.isValid()) {
+ numInvalidGeometries++;
+ System.out.println("Invalid Geoemtry: " + feature.getID());
+ }
+ }
+ }
+
+ ValidationVisitor visitor = new ValidationVisitor();
+
+ // Pass visitor and the progress bar to feature collection
+ featureCollection.accepts(visitor, progress);
+ return visitor.numInvalidGeometries;
+ }
+}
diff --git a/src/main/java/org/geotools/tutorial/feature/Csv2Shape.java b/src/main/java/org/geotools/tutorial/feature/Csv2Shape.java
new file mode 100644
index 0000000..caa039e
--- /dev/null
+++ b/src/main/java/org/geotools/tutorial/feature/Csv2Shape.java
@@ -0,0 +1,212 @@
+package org.geotools.tutorial.feature;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.Point;
+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.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.geotools.swing.data.JFileDataStoreChooser;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This example reads data for point locations and associated attributes from a
+ * comma separated text (CSV) file and exports them as a new shapefile. It illustrates how to build a feature type.
+ *
+ * Note: to keep things simple in the code below the input file should not have additional spaces or
+ * tabs between fields.
+ */
+public class Csv2Shape {
+
+ public static void main(String[] args) throws Exception {
+ File file = new File("res/feature/locations.csv");
+
+ /*
+ * We use the DataUtilities class to create a FeatureType that will describe the data in our
+ * shapefile.
+ * See also the createFeatureType method below for another, more flexible approach.
+ */
+ 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
+ );
+ System.out.println("TYPE:" + TYPE);
+
+ /*
+ * A list to collect features as we create them.
+ */
+ List features = 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);
+
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ try {
+ /* 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 ! */
+ Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
+
+ featureBuilder.add(point);
+ featureBuilder.add(name);
+ featureBuilder.add(number);
+ SimpleFeature feature = featureBuilder.buildFeature(null);
+ features.add(feature);
+ }
+ }
+ } finally {
+ reader.close();
+ }
+
+ /*
+ * Get an output file name and create the new shapefile
+ */
+ File newFile = getNewShapeFile(file);
+
+ ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
+
+ Map 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);
+
+ /*
+ * 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();
+ SimpleFeatureType SHAPE_TYPE = createFeatureType();
+ /*
+ * 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, features);
+ featureStore.setTransaction(transaction);
+ try {
+ featureStore.addFeatures(collection);
+ transaction.commit();
+ } catch (Exception problem) {
+ problem.printStackTrace();
+ transaction.rollback();
+ } finally {
+ transaction.close();
+ }
+ System.exit(0); // success!
+ } else {
+ System.out.println(typeName + " does not support read/write access");
+ System.exit(1);
+ }
+ }
+
+ /**
+ * 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(File csvFile) {
+ 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();
+ if (newFile.equals(csvFile)) {
+ System.out.println("Error: cannot replace " + csvFile);
+ System.exit(0);
+ }
+
+ return newFile;
+ }
+
+ /**
+ * Here is how you can use a SimpleFeatureType builder to create the schema for your shapefile
+ * dynamically.
+ *
+ * This method is an improvement on the code used in the main method above (where we used
+ * DataUtilities.createFeatureType) because we can set a Coordinate Reference System for the
+ * FeatureType and a a maximum field length for the 'name' field dddd
+ */
+ private static SimpleFeatureType createFeatureType() {
+ SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
+ builder.setName("Location");
+ builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference system
+
+ // add attributes in order
+ builder.add("the_geom", Point.class);
+ builder.length(15).add("Name", String.class); // <- 15 chars width for name field
+ builder.add("number",Integer.class);
+
+ // build the type
+ return builder.buildFeatureType();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/geotools/tutorial/quickstart/Quickstart.java b/src/main/java/org/geotools/tutorial/quickstart/Quickstart.java
new file mode 100644
index 0000000..2e14d66
--- /dev/null
+++ b/src/main/java/org/geotools/tutorial/quickstart/Quickstart.java
@@ -0,0 +1,44 @@
+package org.geotools.tutorial.quickstart;
+
+import org.geotools.data.FileDataStore;
+import org.geotools.data.FileDataStoreFinder;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.map.FeatureLayer;
+import org.geotools.map.Layer;
+import org.geotools.map.MapContent;
+import org.geotools.styling.SLD;
+import org.geotools.styling.Style;
+import org.geotools.swing.JMapFrame;
+import org.geotools.swing.data.JFileDataStoreChooser;
+
+import java.io.File;
+
+
+/**
+ * Hello world!
+ */
+public class Quickstart {
+ public static void main(String[] args) throws Exception {
+// // display a data store file chooser dialog for shapefiles
+// File file = JFileDataStoreChooser.showOpenFile("shp", null);
+// if (file == null) {
+// return;
+// }
+ File file = new File("res/quickstart/ne_50m_admin_0_countries.shp");
+
+
+ FileDataStore store = FileDataStoreFinder.getDataStore(file);
+ SimpleFeatureSource featureSource = store.getFeatureSource();
+
+ // Create a map content and add our shapefile to it
+ MapContent map = new MapContent();
+ map.setTitle("Quickstart");
+
+ Style style = SLD.createSimpleStyle(featureSource.getSchema());
+ Layer layer = new FeatureLayer(featureSource, style);
+ map.addLayer(layer);
+
+ // Now display the map
+ JMapFrame.showMap(map);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/geotools/quickstart/QuickstartTest.java b/src/test/java/org/geotools/quickstart/QuickstartTest.java
new file mode 100644
index 0000000..aec444e
--- /dev/null
+++ b/src/test/java/org/geotools/quickstart/QuickstartTest.java
@@ -0,0 +1,38 @@
+package org.geotools.quickstart;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple Quickstart.
+ */
+public class QuickstartTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public QuickstartTest(String testName)
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( QuickstartTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}