Ich möchte mit GeoTools eine Karte erstellen und in einem Bild (zB JPEG) speichern. Meine Anforderungen sind einfach:
- Erstellen Sie eine Weltkarte mit zwei Ebenen: Politische Grenzen und ein Raster. Die Ebenen stammen aus verschiedenen Quellen und verschiedenen Projektionen.
- Geben Sie die Karte in verschiedenen Projektionen aus (z. B. "EPSG: 5070", "EPSG: 4326", "EPSG: 54012", "EPSG: 54009" usw.).
- Clip die Ausgabe auf verschiedene AOIs (zB -124,79 bis -66,9 lon, 24,4 bis 49,4 lat).
Ich möchte dies programmgesteuert über die API tun. Bisher hatte ich nur begrenzten Erfolg. Ich habe gelernt, mit diesem Ansatz eine Karte zu erstellen und in verschiedenen Projektionen auszugeben:
//Step 1: Create map
MapContent map = new MapContent();
map.setTitle("World");
//Step 2: Set projection
CoordinateReferenceSystem crs = CRS.decode("EPSG:5070"); //Conic projection over US
MapViewport vp = map.getViewport();
vp.setCoordinateReferenceSystem(crs);
//Step 3: Add layers to map
CoordinateReferenceSystem mapCRS = map.getCoordinateReferenceSystem();
map.addLayer(reproject(getPoliticalBoundaries(), mapCRS));
map.addLayer(reproject(getGraticules(), mapCRS));
//Step 4: Save image
saveImage(map, "/temp/graticules.jpg", 800);
Die Speichermethode stammt direkt von der GeoTools- Website :
public void saveImage(final MapContent map, final String file, final int imageWidth) {
GTRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
Rectangle imageBounds = null;
ReferencedEnvelope mapBounds = null;
try {
mapBounds = map.getMaxBounds();
double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0);
imageBounds = new Rectangle(
0, 0, imageWidth, (int) Math.round(imageWidth * heightToWidth));
} catch (Exception e) {
// failed to access map layers
throw new RuntimeException(e);
}
BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB);
Graphics2D gr = image.createGraphics();
gr.setPaint(Color.WHITE);
gr.fill(imageBounds);
try {
renderer.paint(gr, imageBounds, mapBounds);
File fileToSave = new File(file);
ImageIO.write(image, "jpeg", fileToSave);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Das Reprojektionsverfahren ist meine Erfindung. Es ist ein bisschen wie ein Hack, aber es ist die einzige Möglichkeit, ein Bild für eine bestimmte Projektion auszugeben.
private static Layer reproject(Layer layer, CoordinateReferenceSystem mapCRS) throws Exception {
SimpleFeatureSource featureSource = (SimpleFeatureSource) layer.getFeatureSource();
//Define coordinate transformation
CoordinateReferenceSystem dataCRS = featureSource.getSchema().getCoordinateReferenceSystem();
boolean lenient = true; // allow for some error due to different datums
MathTransform transform = CRS.findMathTransform(dataCRS, mapCRS, lenient);
//Create new feature collection
SimpleFeatureCollection copy = FeatureCollections.newCollection("internal");
SimpleFeatureType featureType = SimpleFeatureTypeBuilder.retype(featureSource.getSchema(), mapCRS);
SimpleFeatureIterator iterator = featureSource.getFeatures().features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
Geometry geometry = (Geometry) feature.getDefaultGeometry();
Geometry geometry2 = JTS.transform(geometry, transform);
copy.add( SimpleFeatureBuilder.build( featureType, new Object[]{ geometry2 }, null) );
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
iterator.close();
}
//Return new layer
Style style = SLD.createLineStyle(Color.BLACK, 1);
layer = new FeatureLayer(copy, style);
layer.setTitle("Graticules");
return layer;
}
Die Ausgabe ist wirklich schlecht:
Ich glaube, ich habe ein paar verschiedene Fragen:
- Ist das der richtige Ansatz? Muss ich Ebenen wirklich manuell neu projizieren oder soll das MapViewport dies für mich tun?
- Wie schneide ich die Ausgabe an eine bestimmte AOI? Ich habe versucht, die Grenzen mit der MapViewport.setBounds-Methode (Hüllkurve) festzulegen, aber die saveImage-Methode scheint die Grenzen zu ignorieren.
- Wie kann ich meine Breitengradlinien als Bögen rendern lassen? Gibt es eine Transformationseinstellung, die mir fehlt?
Ich benutze GeoTools 8.7.