GeoTools : Putting everything together

GeoTools 2.1 Tutorial

Icon

The following tutorial will only work with GeoTools 2.1; StyledMapPane has been removed.

The replacement is called "JMapPane" and is only intended for examples. Sample use available FOSS4G 2006 Presentation here.

Note: the ArcGridDataSource used below is deprecated and was replaced by a GridCoverageExchange implementation (will be in the 2.1 release).

Let's review what we have seen by creating a small map. The map data is available in the CVS repository in the sample data module, but I've attached it to this page too. If you want to use the attached data, you will just need to change the URLs so that they point to your local filesystem instead of using the classpath.

In order to build a map you need to:

  • Get the feature sources with the data you want to display from the feature store, or the feature collection from the data sources (if you need to use an older data source that has not yet been converted to the newer data store interface).
  • Build an appropriate style for each feature source. Here we will use the StyleBuilder to ease the tedious building of a full Style object.
  • Create a MapContext and add the layers: made up of the feature sources and the styles
  • Create a MapPane to display the MapContext contents on the screen.

The full source code is attached to this page. Here we will examine the source code section by section.

First, let's load the FeatureSources and the FeatureCollections. Please refer to the Data access basic for more information about data sources. One small note about the DEM loading: as you can see an ArcGrid data source is used, giving us a feature collection. The feature collection will contain a single Feature that in turn wraps the GridCoverage that really has the DEM in it.

 // Prepare feature sources		
// .. digital elevation dem. 
URL demURL = getResource("org/geotools/sampleData/spearfish_dem.asc.gz");
// .. If you are working with files from the local file system, use the 
// following line instead
// URL demURL = (new java.io.File("/path/to/spearfish/dem")).toURL();
ArcGridDataSource dsDem = new ArcGridDataSource(demURL);
dsDem.setUseGzipCompression(true);
dsDem.setGRASSFormatEnabled(true);
FeatureCollection fcDem = dsDem.getFeatures();
// .. roads
URL roadsURL = getResource("org/geotools/sampleData/roads.shp");
ShapefileDataStore dsRoads = new ShapefileDataStore(roadsURL);
FeatureSource fsRoads = dsRoads.getFeatureSource("roads");
// .. streams
URL streamsURL = getResource("org/geotools/sampleData/streams.shp");
ShapefileDataStore dsStreams = new ShapefileDataStore(streamsURL);
FeatureSource fsStreams = dsStreams.getFeatureSource("streams");
// .. bug sites
URL bugURL = getResource("org/geotools/sampleData/bugsites.shp");
ShapefileDataStore dsBugs = new ShapefileDataStore(bugURL);
FeatureSource fsBugs = dsBugs.getFeatureSource("bugsites");
// .. arch sites
URL archURL = getResource("org/geotools/sampleData/archsites.shp");
ShapefileDataStore dsArch = new ShapefileDataStore(archURL);
FeatureSource fsArch = dsArch.getFeatureSource("archsites");
// .. restricted aread
URL restrictedURL = getResource("org/geotools/sampleData/rstrct.shp");
ShapefileDataStore dsRectricted = new ShapefileDataStore(restrictedURL);
FeatureSource fsRestricted = dsRectricted.getFeatureSource("rstrct");

Next, let's create styles. The streams style will be a blue line, 3 pixels wide:

// .. streams style
LineSymbolizer lsStream = sb.createLineSymbolizer(Color.BLUE, 3);
Style streamsStyle = sb.createStyle(lsStream);

The roads style will be a composite style, with a yellow centerline and a black wider line under it. To avoid visual problems at crossings, we will build it with two separate feature type styles instead of using a rule with two symbolizers:

// .. roads style
LineSymbolizer ls1 = sb.createLineSymbolizer(Color.YELLOW, 1);
LineSymbolizer ls2 = sb.createLineSymbolizer(Color.BLACK, 5);
Style roadsStyle = sb.createStyle();
roadsStyle.addFeatureTypeStyle(sb.createFeatureTypeStyle(null, sb.createRule(ls2)));
roadsStyle.addFeatureTypeStyle(sb.createFeatureTypeStyle(null, sb.createRule(ls1)));

The archeological sites will be depicted as a small yellow triangle and a label with the name of the archeological site. The name is contained in the "CAT_DESC" attribute of the shapefile, and we are going to tell the text symbolizer this. Also notice the halo, that will be drawn around the text in order to make it more readable.
In this case we will create a rule with two symbolizers, since we don't have crossing problems here.

// .. archeological sites style
Mark yellowTri = sb.createMark(StyleBuilder.MARK_TRIANGLE, Color.YELLOW, Color.BLACK, 0);
Graphic grArch = sb.createGraphic(null, yellowTri, null, 1, 15, 0);
PointSymbolizer psArch = sb.createPointSymbolizer(grArch);
org.geotools.styling.Font font = sb.createFont(new Font("Arial", Font.PLAIN, 12));
TextSymbolizer tsArch = sb.createTextSymbolizer(Color.BLACK, font, "CAT_DESC");
tsArch.setHalo(sb.createHalo(Color.WHITE, 1, 2));
Style archStyle = sb.createStyle();
archStyle.addFeatureTypeStyle(sb.createFeatureTypeStyle(null, sb.createRule(psArch)));
archStyle.addFeatureTypeStyle(sb.createFeatureTypeStyle(null, sb.createRule(tsArch)));

The bug sites will be depicted as small red circles. The code is very similar to that above, so it is omitted here.

The restricted areas will be depicted as gray translucent polygons by giving them an opacity of less than 1.0:

PolygonSymbolizer restrictedSymb = sb.createPolygonSymbolizer(Color.LIGHT_GRAY, Color.BLACK, 0);
restrictedSymb.getFill().setOpacity(sb.literalExpression(0.7));
Style restrictedStyle = sb.createStyle(restrictedSymb);

Finally, we will create a style for the DEM. Here we are going to provide a special color map that associates a certain height with a certain color, and generates a color ramp for intermediate values:

ColorMap cm =
    sb.createColorMap(
        new double[] { 1000, 1200, 1400, 1600, 2000 },
        new Color[] {
            new Color(0, 255, 0),
            new Color(255, 255, 0),
            new Color(255, 127, 0),
            new Color(191, 127, 63),
            new Color(255, 255, 255)},
        ColorMap.TYPE_RAMP);
RasterSymbolizer rsDem = sb.createRasterSymbolizer(cm, 1);
Style demStyle = sb.createStyle(rsDem);

Once the styles are ready, building the map and showing it is a snap:

// Build the map
MapContext map = new DefaultMapContext();
map.addLayer(fcDem, demStyle);
map.addLayer(fsStreams, streamsStyle);
map.addLayer(fsRoads, roadsStyle);
map.addLayer(fsRestricted, restrictedStyle);
map.addLayer(fsBugs, bugsStyle);
map.addLayer(fsArch, archStyle);

// Show the map
StyledMapPane mapPane = new StyledMapPane();
mapPane.setMapContext(map);
mapPane.getRenderer().addLayer(new RenderedMapScale());
JFrame frame = new JFrame();
frame.setTitle("Spearfish map");
frame.setContentPane(mapPane.createScrollPane());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(640, 480);
frame.show();

Here is a screenshot of the resulting map pane, where you can see:

  • the map;
  • the magnifier;
  • the map pane commands, listed in the context menu.

In conclusion, a word of caution about using the MapPane: the MapPane in its current state is not a finished part of the API and will be changed once we complete the GUI components design. If you wish to help, please share your opinions and help us in the GUI components design page.