14
nvironmental ngineering ydroloGIS HydroloGIS S.r.l. - Via Siemens, 19 - 39100 Bolzano www.hydrologis.com Java Open Source GIS Development From the building blocks to extending an existing GIS application. Geoinformation Research Group, Department of Geography University of Potsdam August 2011 Part 4: Raster data Tutor: Andrea Antonello

Opensource gis development - part 4

Embed Size (px)

DESCRIPTION

Fourth part of the Course "Java Open Source GIS Development - From the building blocks to extending an existing GIS application." held at the University of Potsdam in August 2011

Citation preview

Page 1: Opensource gis development - part 4

nvironmental ngineeringydroloGISHydroloGIS S.r.l. - Via Siemens, 19 - 39100 Bolzano www.hydrologis.com

Java Open Source GISDevelopment

From the building blocks to extendingan existing GIS application.

Geoinformation Research Group, Department of GeographyUniversity of Potsdam

August 2011

Part 4: Raster dataTutor: Andrea Antonello

Page 2: Opensource gis development - part 4

Working with Raster data

When we talk about raster data in GIS we usually mean digital

elevation/terrain/surface models (DEM/DTM/DSM). DEMs can be used to

extract various attributes useful for hydrologic, geomorphologic analyses.

From the DEM maps like aspect, flowdirections, curvatures, gradient and

extracted network can be calculated.

As seen in part 1, a raster is composed of cells and has a value in every cell.

A DEM is a raster that has in every cell the elevation value in that position.

Handling raster data is on one hand trickier than vector data in GeoTools, the

upside is that raster data are so simple, that there is few we need to learn to

be able to process them.

Page 3: Opensource gis development - part 4

Reading a raster map

The perhaps simplest format for raster data is the ascii grid. An ascii grid is a

cleartext format that contains:

• a header with:

• the information of the position of the raster (lower left corner)

• the size of the cells

• the number used as novalue

• the matrix of the data

The dataset we will use for our tests is the spearfish dataset. Please

download it and unzip it in /home/moovida/giscourse/data.

Page 4: Opensource gis development - part 4

While creating a raster from scratch is not all that easy in GeoTools, reading

it from a map file, is quite easy. All the hard work is done by the coverage

readers, as in the following case by the ArcGridReader:

ArcGridReader asciiGridReader = new ArcGridReader(file); GridCoverage2D readRaster = asciiGridReader.read(null); // make sure to get the actual data readRaster = readRaster.view(ViewType.GEOPHYSICS); asciiGridReader.dispose();

The same concept applies to the writing of raster maps. Once we have the

GridCoverage2D that we want to write to file, we just need the appropriate

writer class:

ArcGridWriter asciiGridWriter = new ArcGridWriter(file); asciiGridWriter.write(readRaster, null); asciiGridWriter.dispose();

This obviously makes it easy to create a tool to transform between formats.

Page 5: Opensource gis development - part 4

To view the newly written geotiff raster map, we first need to read it again:

GeoTiffReader geoTiffReader = new GeoTiffReader(file); readRaster = geoTiffReader.read(null); // readRaster = readRaster.view(ViewType.GEOPHYSICS); geoTiffReader.dispose();

and pass it with a default style to the map viewer:

MapContext map = new MapContext(); map.setTitle("Grid"); map.setCoordinateReferenceSystem(readRaster.getCoordinateReferenceSystem()); StyleFactory sf = CommonFactoryFinder.getStyleFactory(GeoTools.getDefaultHints()); Style style = SLD.wrapSymbolizers(sf.createRasterSymbolizer()); map.addLayer(readRaster, style); JMapFrame.showMap(map);

You should see something like:

Page 6: Opensource gis development - part 4

Processing a raster map

Processing a raster map basically means doing something with the values

contained in every cell of the map.

To do so we need to be able to iterate over the cells. But first we need to

have the concept of image space and world space clear. Assuming we are

placed north of the equator, the following holds:

value

cols

rows

x

y

0,0

2

grid space

world space

1

easting

northing

Page 7: Opensource gis development - part 4

In the grid space

Accessing the raster in the grid/image space is usually easier understood.

Most of the times the origin of a raster map is in row = 0 and col = 0 and has

a well defined width and height. Attributes like these can be easily obtained

from the GridCoverage2D through the JGrasstools API:

RegionMap regionMap = CoverageUtilities.getRegionParamsFromGridCoverage(readRaster); int rows = regionMap.getRows(); int cols = regionMap.getCols();

Everything boils down to an iteration over cols and rows to access every cell

through the evaluate method. As an example let's calculate the sum of all

the values and the average elevation of the test DEM:

double sum = 0; double[] values = new double[1]; for( int c = 0; c < cols; c++ ) { for( int r = 0; r < rows; r++ ) { readRaster.evaluate(new GridCoordinates2D(c, r), values); sum = sum + values[0]; } } double avg = sum / (rows * cols);

Page 8: Opensource gis development - part 4

In the world space

When working in the world space, the only thing that changes, is that when

iterating over the position, the bounds and resolution of the raster has to be

considered. They can be obtained from the RegionMap object already used

for the rows and cols:

double west = regionMap.getWest(); double east = regionMap.getEast(); double south = regionMap.getSouth(); double north = regionMap.getNorth(); double xres = regionMap.getXres(); double yres = regionMap.getYres();

Then, we can move cell by cell through the world coordinates:

sum = 0; values = new double[1]; for( double easting = west + xres / 2.0; easting < east; easting = easting + xres ) { for( double northing = south + yres / 2.0; northing < north; northing = northing + yres ) { readRaster.evaluate(new Point2D.Double(easting, northing), values); sum = sum + values[0]; } } avg = sum / (rows * cols);

Page 9: Opensource gis development - part 4

Writing a raster map

In the previous examples we calculated some simple statistics. Most of the

time the result of a GIS elaboration will be a new raster map that we also

need to write to a file.

As an exercise, let's bring the spearfish mountains to the sea. This basically

means to:

1. search the minimum value of the map

2. create a new raster into which to put the result

3. subtract the minimum to every value and write the result into the new

raster

4. write the raster to disk

Page 10: Opensource gis development - part 4

Find minimum:

double min = Double.POSITIVE_INFINITY; for( int c = 0; c < cols; c++ ) { for( int r = 0; r < rows; r++ ) { readRaster.evaluate(new GridCoordinates2D(c, r), values); min = Math.min(values[0], min); } }

Create an empty new raster to put the result in:

WritableRaster newWritableRaster = CoverageUtilities.createDoubleWritableRaster(// cols, rows, null, null, null);

Note that the raster has been defined only by rows and cols, it lives in the

image space and has no idea were on the world it will be placed.

Make mountains crumble to the sea:

for( int c = 0; c < cols; c++ ) { for( int r = 0; r < rows; r++ ) { readRaster.evaluate(new GridCoordinates2D(c, r), values); newWritableRaster.setSample(c, r, 0, values[0] - min); } }

Page 11: Opensource gis development - part 4

Give the resulting raster a geographic context:

CoordinateReferenceSystem crs = readRaster.getCoordinateReferenceSystem(); GridCoverage2D newRaster = CoverageUtilities.buildCoverage(// "raster", newWritableRaster, regionMap, crs);

Check the result by loading the read and processed raster in a viewer and

quering the elevation.

Page 12: Opensource gis development - part 4

From rows/cols to easting/northing and back

The transformation between the two domanis can be done directly from the

GridGeometry.

GridGeometry2D gridGeometry = readRaster.getGridGeometry();

Image -> World

int row = 100; int col = 50; DirectPosition world = gridGeometry.gridToWorld(new GridCoordinates2D(col, row)); double[] worldArray = world.getCoordinate(); Coordinate worldCoord = new Coordinate(worldArray[0], worldArray[1]);

World -> Image

double easting = 591825.0; double northing = 4924635.0; GridCoordinates2D grid = gridGeometry.worldToGrid(new DirectPosition2D(easting, northing)); col = grid.x; row = grid.y;

Page 13: Opensource gis development - part 4

Exercises

• reclassify the spearfish elevation map to have

• nv: min - 1200.0

• 1: 1200.0 - 1500.0

• 2: 1500.0 - 1800.0

• 3: 1800.0 - max

• create a map that contains only the values between 1200.0 and 1400.0

Advanced exercises with mixed raster/vector flavour:

• create the profile of the raster, based on a horizontal LineString that

passes through the middle of the map

• create a raster map that has the spearfish elevation values only inside a

rectangle that is given by the original raster bounding box shrinked by a

quarter on each side

Page 14: Opensource gis development - part 4

This work is released under Creative Commons Attribution ShareAlike (CC-BY-SA)

Much of the knowledge needed to create this training material hasbeen produced by the sparkling knights of the GeoTools, JTS anduDig community. Another essential source has been the Wikipediacommunity effort.

Particular thanks go to those friends that directly or indirectly helpedout in the creation and review of this developer's handbook: JodyGarnett from the uDig/GeoTools community and the TANTO team.

This tutorial was written with the support of the GeoinformationResearch Group of the University of Potsdam and HydroloGIS.