4

I'm trying to get a JMapPane to show up in a JPanel, but without success. Below is the JPanel instance containing the map. I am importing a geotiff and a shapefile layered in that order. Not only does the geotiff raster layer not show up, but the shapefile is displayed backwards. What am I doing wrong?

Screenshot

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

import javax.swing.JPanel;

import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.map.FeatureLayer;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.ContrastEnhancement;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.SLD;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.geotools.swing.JMapPane;
import org.opengis.filter.FilterFactory2;
import org.opengis.style.ContrastMethod;

public class MapImagePanel extends JPanel {

private static final long serialVersionUID = -7924289582676785758L;
private File blueMarble = null;
private File borderShape = null;
private GridCoverage2DReader gridCoverage2DReader;
private StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();

public StyleFactory getStyleFactory() {
    return styleFactory;
}

private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();

public MapImagePanel() {
    this.setLayout(new BorderLayout(0, 0));
    this.setBackground(Color.BLUE);
    this.setPreferredSize(new Dimension(720, 360));

    try {
        this.setBlueMarble(new File(this.getClass().getResource("/gis/BlueMarbleNG_2004-12-01_rgb_720x360.tiff").toURI()));
    } catch (URISyntaxException e1) {
        e1.printStackTrace();
    }

    try {
        this.setBorderShape(new File(this.getClass().getResource("/gis/world_borders/TM_WORLD_BORDERS-0.3.shp").toURI()));
    } catch (URISyntaxException e1) {
        e1.printStackTrace();
    }

    try {
        this.displayLayers();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void displayLayers() throws Exception {
    AbstractGridFormat format = GridFormatFinder.findFormat(this.getBlueMarble());
    this.setGridCoverageReader(format.getReader(this.getBlueMarble()));

    Style rgbStyle = this.createRGBStyle();

    // connect to the shapefile
    FileDataStore dataStore = FileDataStoreFinder.getDataStore(this.getBorderShape());
    SimpleFeatureSource shapefileSource = dataStore.getFeatureSource();

    Style shpStyle = SLD.createPolygonStyle(Color.BLUE, null, 0.0f);

    final MapContent map = new MapContent();
    map.setTitle("LogMap");

    Layer rasterLayer = new GridReaderLayer(this.getGridCoverageReader(), rgbStyle);
    map.addLayer(rasterLayer);

    Layer shpLayer = new FeatureLayer(shapefileSource, shpStyle);
    map.addLayer(shpLayer);

    JMapPane mapPane = new JMapPane();
    mapPane.setMapContent(map);
    //mapPane.setDisplayArea(shapefileSource.getBounds());
    mapPane.setDisplayArea(this.getGridCoverageReader().getOriginalEnvelope());

    this.add(mapPane, BorderLayout.CENTER);
}

// docs start create rgb style
/**
 * This method examines the names of the sample dimensions in the provided
 * coverage looking for "red...", "green..." and "blue..." (case insensitive
 * match). If these names are not found it uses bands 1, 2, and 3 for the
 * red, green and blue channels. It then sets up a raster symbolizer and
 * returns this wrapped in a Style.
 *
 * @return a new Style object containing a raster symbolizer set up for RGB
 *         image
 */
private Style createRGBStyle() {
    GridCoverage2DReader reader = this.getGridCoverageReader();
    StyleFactory sf = this.getStyleFactory();
    GridCoverage2D cov = null;
    try {
        cov = reader.read(null);
    } catch (IOException giveUp) {
        throw new RuntimeException(giveUp);
    }
    // We need at least three bands to create an RGB style
    int numBands = cov.getNumSampleDimensions();
    if (numBands < 3) {
        return null;
    }
    // Get the names of the bands
    String[] sampleDimensionNames = new String[numBands];
    for (int i = 0; i < numBands; i++) {
        GridSampleDimension dim = cov.getSampleDimension(i);
        sampleDimensionNames[i] = dim.getDescription().toString();
    }
    final int RED = 0, GREEN = 1, BLUE = 2;
    int[] channelNum = { -1, -1, -1 };
    // We examine the band names looking for "red...", "green...",
    // "blue...".
    // Note that the channel numbers we record are indexed from 1, not 0.
    for (int i = 0; i < numBands; i++) {
        String name = sampleDimensionNames[i].toLowerCase();
        if (name != null) {
            if (name.matches("red.*")) {
                channelNum[RED] = i + 1;
            } else if (name.matches("green.*")) {
                channelNum[GREEN] = i + 1;
            } else if (name.matches("blue.*")) {
                channelNum[BLUE] = i + 1;
            }
        }
    }
    // If we didn't find named bands "red...", "green...", "blue..."
    // we fall back to using the first three bands in order
    if (channelNum[RED] < 0 || channelNum[GREEN] < 0
            || channelNum[BLUE] < 0) {
        channelNum[RED] = 1;
        channelNum[GREEN] = 2;
        channelNum[BLUE] = 3;
    }
    // Now we create a RasterSymbolizer using the selected channels
    SelectedChannelType[] sct = new SelectedChannelType[cov
            .getNumSampleDimensions()];
    ContrastEnhancement ce = sf.contrastEnhancement(this.ff.literal(1.0),
            ContrastMethod.NORMALIZE);
    for (int i = 0; i < 3; i++) {
        sct[i] = sf.createSelectedChannelType(
                String.valueOf(channelNum[i]), ce);
    }

    RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
    ChannelSelection sel = sf.channelSelection(sct[RED], sct[GREEN],
            sct[BLUE]);
    sym.setChannelSelection(sel);

    return SLD.wrapSymbolizers(sym);
}

public File getBorderShape() {
    return borderShape;
}

public void setBorderShape(File borderShape) {
    this.borderShape = borderShape;
}

public File getBlueMarble() {
    return blueMarble;
}

public void setBlueMarble(File blueMarble) {
    this.blueMarble = blueMarble;
}

public GridCoverage2DReader getGridCoverageReader() {
    return gridCoverage2DReader;
}

public void setGridCoverageReader(GridCoverage2DReader gridCoverage2DReader) {
    this.gridCoverage2DReader = gridCoverage2DReader;
}

}

UPDATE

Added a few lines and now have the shapefile borders showing up correctly, but the geotiff is still missing.

Under the displayLayers() method I added:

...
mapPane.setMapContent(map);
mapPane.setDisplayArea(shapefileSource.getBounds());
...

This is the result: working shapefile

  • 1
    What projection is the raster in? – Ian Turton Nov 11 '14 at 20:05
  • Viewing the metadata in QGIS, it reports Latitude/Longitude projection with a WGS84 datum. – cj5 Nov 11 '14 at 20:11
2
+50

This seems to work for me - I'm using the Admin Boundaries from Natural Earth and a Blue Marble jpeg (with a hand cranked world file) and this code which gives me this image.

Without seeing your actual datafiles my suspicion is that you have a tiff file with either no world file or a broken one instead of a geotiff. If that is the case then you should be seeing some sort of error message on the console.

map of the world

  • I've been using the Blue Marble tiffs from unearthedoutdoors.net/global_data/true_marble/download I always assumed that geotiffs contained any of the data I needed. – cj5 Dec 8 '14 at 17:27
  • 1
    Mapframe just puts it into a pane. – Ian Turton Dec 8 '14 at 18:33
  • 1
    I've just tried it with your tif and they have a broken CRS (it's long/lat instead of lat/long) - you could probably fix it with gdaltransform but I'd just use the NASA ones which do work. – Ian Turton Dec 9 '14 at 8:18
  • 1
    you should be able to add a .proj file (download from epsg.io) in this case epsg:4326 and WGS84 are the same(ish). – Ian Turton Dec 9 '14 at 17:38
  • 1
    bad world file? - see en.wikipedia.org/wiki/World_file – Ian Turton Dec 10 '14 at 12:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.