Table of Contents
-
- foreword
- CRS Lab Application
- expand
-
- Geometry
Foreword
The main content of this chapter is the transformation of the projected graphics coordinate system
CRS Lab Application
First, import the required dependencies
<dependencies> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-shapefile</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-swing</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-epsg-hsql</artifactId> <version>${geotools.version}</version> </dependency> </dependencies> <repositories> <repository> <id>osgeo</id> <name>OSGeo Release Repository</name> <url>https://repo.osgeo.org/repository/release/</url> <snapshots><enabled>false</enabled></snapshots> <releases><enabled>true</enabled></releases> </repository> <repository> <id>osgeo-snapshot</id> <name>OSGeo Snapshot Repository</name> <url>https://repo.osgeo.org/repository/snapshot/</url> <snapshots><enabled>true</enabled></snapshots> <releases><enabled>false</enabled></releases> </repository> </repositories>
Then create our CRSLab class
public class CRSLab {<!-- --> private File sourceFile; private SimpleFeatureSource featureSource; private MapContent map; public static void main(String[] args) throws Exception {<!-- --> CRSLab lab = new CRSLab(); lab.displayShapefile(); }
Here, the CRSLab class is new in the main, and the displayShapefile method is executed. It can be seen from the name that it is a method for displaying shapefiles. See below for the specific implementation
private void displayShapefile() throws Exception {<!-- --> sourceFile = JFileDataStoreChooser. showOpenFile("shp", null); if (sourceFile == null) {<!-- --> return; } FileDataStore store = FileDataStoreFinder.getDataStore(sourceFile); featureSource = store. getFeatureSource(); // Create a map context and add our shapefile to it map = new MapContent(); Style style = SLD.createSimpleStyle(featureSource.getSchema()); Layer layer = new FeatureLayer(featureSource, style); map.layers().add(layer); // Create a JMapFrame with custom toolbar buttons JMapFrame mapFrame = new JMapFrame(map); mapFrame.enableToolBar(true); mapFrame.enableStatusBar(true); JToolBar toolbar = mapFrame. getToolBar(); toolbar. addSeparator(); toolbar.add(new JButton(new ValidateGeometryAction())); toolbar.add(new JButton(new ExportShapefileAction())); // Display the map frame. When it is closed the application will exit mapFrame. setSize(800, 600); mapFrame. setVisible(true); }
In the displayShapefile method, first use the file selector JFileDataStoreChooser.showOpenFile("shp", null);
to select the shapefile. Then create a map container new MapContent();
and a map frame new JMapFrame(map);
to display the loaded shapefile. There is nothing to say about this step, the key point is below, we added two buttons to the ToolBar of the map frame
JToolBar toolbar = mapFrame.getToolBar(); toolbar. addSeparator(); toolbar.add(new JButton(new ValidateGeometryAction())); toolbar.add(new JButton(new ExportShapefileAction()));
And define two classes new ValidateGeometryAction()
and new ExportShapefileAction()
for the two buttons as the execution content after the button is clicked, the key of this article is also in these two between classes.
first look at the first
class ValidateGeometryAction extends SafeAction {<!-- --> ValidateGeometryAction() {<!-- --> super("Validate geometry"); putValue(Action. SHORT_DESCRIPTION, "Check each geometry"); } public void action(ActionEvent e) throws Throwable {<!-- --> int numInvalid = validateFeatureGeometry(null); String msg; if (numInvalid == 0) {<!-- --> msg = "All feature geometries are valid"; } else {<!-- --> msg = "Invalid geometries: " + numInvalid; } JOptionPane.showMessageDialog( null, msg, "Geometry results", JOptionPane. INFORMATION_MESSAGE); } }
You can see that this class inherits the SafeAction class
By browsing the source code, we can see that SafeAction is a subclass of AbstractAction, which belongs to its “safe version”, and it will record all error messages. And AbstractAction is the implementation of the JFC Action interface, which is the interface for execution (it is a bit difficult to describe here, if you are interested, you can check the source code, if you are not interested, you only need to know that we inherit SafeAction and rewrite its action method to realize the function of the button ok)
Another method validateFeatureGeometry(null)
is called in the action method
The details of the method are as follows
private int validateFeatureGeometry(ProgressListener progress) throws Exception {<!-- --> final SimpleFeatureCollection featureCollection = featureSource. getFeatures(); // Rather than use an iterator, create a FeatureVisitor to check each feature 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 & amp; & amp; !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; }
Its role is to verify whether the feature graphics in the shapefile are legal, and return the number of legal features in the above read features. The function of this button is to verify the number of legal features in the imported shapefile.
Look at the class of the second button
class ExportShapefileAction extends SafeAction {<!-- --> ExportShapefileAction() {<!-- --> super("Export..."); putValue(Action.SHORT_DESCRIPTION, "Export using current crs"); } public void action(ActionEvent e) throws Throwable {<!-- --> exportToShapefile(); } }
This class calls the method exportToShapefile()
private void exportToShapefile() throws Exception {<!-- --> SimpleFeatureType schema = featureSource. getSchema(); JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); chooser.setDialogTitle("Save reprojected shapefile"); chooser.setSaveFile(sourceFile); int returnVal = chooser. showSaveDialog(null); if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) {<!-- --> return; } File file = chooser. getSelectedFile(); if (file. equals(sourceFile)) {<!-- --> JOptionPane.showMessageDialog(null, "Cannot replace " + file); return; } CoordinateReferenceSystem dataCRS = schema. getCoordinateReferenceSystem(); CoordinateReferenceSystem worldCRS = map.getCoordinateReferenceSystem(); boolean lenient = true; // allow for some error due to different datums MathTransform transform = CRS.findMathTransform(dataCRS, worldCRS, lenient); \t\t SimpleFeatureCollection featureCollection = featureSource. getFeatures(); Transaction transaction = new DefaultTransaction("Reproject"); try (FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriterAppend(createdName, transaction); SimpleFeatureIterator iterator = featureCollection. features()) {<!-- --> while (iterator.hasNext()) {<!-- --> // copy the contents of each feature and transform the geometry SimpleFeature feature = iterator. next(); SimpleFeature copy = writer. next(); copy.setAttributes(feature.getAttributes()); Geometry geometry = (Geometry) feature. getDefaultGeometry(); Geometry geometry2 = JTS. transform(geometry, transform); copy.setDefaultGeometry(geometry2); writer. write(); } transaction.commit(); JOptionPane.showMessageDialog(null, "Export to shapefile complete"); } catch (Exception problem) {<!-- --> problem. printStackTrace(); transaction. rollback(); JOptionPane.showMessageDialog(null, "Export to shapefile failed"); } finally {<!-- --> transaction. close(); } }
It can be seen from the name that it is a class that exports shapefiles, or look at the functions line by line
The first is to choose the location to save the file
SimpleFeatureType schema = featureSource. getSchema(); JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); chooser.setDialogTitle("Save reprojected shapefile"); chooser.setSaveFile(sourceFile); int returnVal = chooser. showSaveDialog(null); if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) {<!-- --> return; } File file = chooser. getSelectedFile(); if (file. equals(sourceFile)) {<!-- --> JOptionPane.showMessageDialog(null, "Cannot replace " + file); return; }
Then convert the coordinates
CoordinateReferenceSystem dataCRS = schema. getCoordinateReferenceSystem(); CoordinateReferenceSystem worldCRS = map.getCoordinateReferenceSystem(); boolean lenient = true; // allow for some error due to different datums MathTransform transform = CRS.findMathTransform(dataCRS, worldCRS, lenient);
Here, the coordinate system of the source shapefile is first obtained, and then the left side of the map container is obtained, and then the mathematical method transform between the two is established.
The following creates a feature type for the exported shapefile
DataStoreFactorySpi factory = new ShapefileDataStoreFactory(); Map<String, Serializable> create = new HashMap<>(); create.put("url", file.toURI().toURL()); create. put("create spatial index", Boolean. TRUE); DataStore dataStore = factory. createNewDataStore(create); SimpleFeatureType featureType = SimpleFeatureTypeBuilder. retype(schema, worldCRS); dataStore. createSchema(featureType); // Get the name of the new Shapefile, which will be used to open the FeatureWriter String createdName = dataStore. getTypeNames()[0];
Finally, create a transaction to add all the elements of the source shapefile to the new file after converting the coordinate system
SimpleFeatureCollection featureCollection = featureSource.getFeatures(); Transaction transaction = new DefaultTransaction("Reproject"); try (FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriterAppend(createdName, transaction); SimpleFeatureIterator iterator = featureCollection. features()) {<!-- --> while (iterator.hasNext()) {<!-- --> // copy the contents of each feature and transform the geometry SimpleFeature feature = iterator. next(); SimpleFeature copy = writer. next(); copy.setAttributes(feature.getAttributes()); Geometry geometry = (Geometry) feature. getDefaultGeometry(); Geometry geometry2 = JTS. transform(geometry, transform); copy.setDefaultGeometry(geometry2); writer. write(); } transaction.commit(); JOptionPane.showMessageDialog(null, "Export to shapefile complete"); } catch (Exception problem) {<!-- --> problem. printStackTrace(); transaction. rollback(); JOptionPane.showMessageDialog(null, "Export to shapefile failed"); } finally {<!-- --> transaction. close(); }
It can be seen that the transform method of JTS is used here and the source geometry and transformed transform are passed in to transform the coordinate system.
Finally, run the main method.
Expand
Geometry
Geometry is actually the shape of GIS, which is the geometric shape of elements.
Here are a few typical Geometries and how they are created
Point
GeometryFactory geometryFactory = JTSFactoryFinder. getGeometryFactory(null); WKTReader reader = new WKTReader(geometryFactory); Point point = (Point) reader. read("POINT (1 1)");
Line
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); WKTReader reader = new WKTReader(geometryFactory); LineString line = (LineString) reader.read("LINESTRING(0 2, 2 0, 8 6)");