Je voudrais créer une carte avec GeoTools et l'enregistrer dans une image (par exemple JPEG). Mes exigences sont simples:
- Créez une carte du monde avec 2 couches: limites politiques et graticule. Les couches proviennent de différentes sources et de différentes projections.
- Sortie de la carte dans différentes projections (par exemple "EPSG: 5070", "EPSG: 4326", "EPSG: 54012", "EPSG: 54009", etc.)
- Coupez la sortie sur différents AOI (par exemple -124,79 à -66,9 lon, 24,4 à 49,4 lat).
Je veux le faire par programme, via l'API. Jusqu'à présent, j'ai eu un succès limité. J'ai appris à créer une carte et une sortie dans diverses projections en utilisant cette approche:
//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);
La méthode de sauvegarde est directement issue du site Web GeoTools :
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);
}
}
La méthode du reprojet est mon invention. C'est un peu un hack mais c'est le seul moyen que j'ai pu trouver pour sortir une image sur une projection spécifique.
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;
}
La sortie est vraiment mauvaise:
Donc, je suppose que j'ai quelques questions différentes:
- Est-ce la bonne approche? Dois-je vraiment reprojeter les couches manuellement ou est-ce que MapViewport est censé le faire pour moi?
- Comment découper la sortie sur une zone d'intérêt spécifique? J'ai essayé de définir les limites à l'aide de la méthode MapViewport.setBounds (enveloppe) mais la méthode saveImage semble ignorer les limites.
- Comment obtenir le rendu de mes lignes de latitude sous forme d'arcs? Y a-t-il un paramètre de transformation qui me manque?
J'utilise GeoTools 8.7.