Executing existing processes with a script

This tutorial will show how to create a script that executes existing WPS processes using Python bindings.

Process definition

This tutorial will create a process called “Buffer and Split”. As its name suggests, it will combine two separate processes, Buffer (geo:buffer) and Split Polygon (geo:splitPolygon). The Buffer process takes as input any geometry and a distance value, and returns a polygon representing the input geometry enlarged by the given distance around its exterior. The Split Polygon process takes as inputs a geometry (usually a polygon) and a linestring, and returns a geometry (usually a geometry collection) generated by splitting the input geometry by the linestring.

The Buffer and Split operation combines these two processes in the following way: it takes as input a geometry, a linestring, and a distance value. The input geometry is buffered by the distance value, and the resulting polygon is split by the linestring. The result, in all but the most trivial cases, will be a polygon or a geometry collection.

../../_images/processcomposite_theory.png

Buffer and Split process

Distance is measured in the same units as the source geometry. It will be assumed that all input geometries are represented in the same units and coordinate reference system.

Note

There are optional inputs to these two source processes that won’t be provided in our script. In cases where optional process inputs are omitted, the processes will use defaults. To see more details about the geo:buffer and geo:splitPolygon processes, as well as a list of every process published in GeoServer, please go to the GeoServer web admin page and click on WPS Processes.

Authoring the script

The complete script is as follows (Download): :

from geoserver.wps import process
from geoscript.process import Process
from geoscript.geom import *

buffer = Process.lookup('geo:buffer')
split = Process.lookup('geo:splitPolygon')

@process(
  title = 'Buffer and Split',
  description = 'Buffers a geometry and splits the resulting polygon.',
  inputs = {
    'geom': (Geometry, 'The geometry to buffer'),
    'dist': (float, 'The distance by which to buffer the target geometry'),
    'line': (LineString, 'The line used for splitting the buffered geometry')
  },
  outputs = {
    'result': (Geometry, 'The buffered and split geometry')
  }
)
def run(geom, dist, line):

  buffered = buffer.run(geom=geom, distance=dist)['result']
  return split.run(polygon=buffered, line=line)['result']

Save as bufferSplit.py. A description of the script functionality follows.

Process headers

The script requires a number of import statements, including geometry types and WPS process hooks. In particular, the Buffer and SplitPolygon processes are pulled in here for use later on.

from geoserver.wps import process
from geoscript.process import Process
from geoscript.geom import *

buffer = Process.lookup('geo:buffer')
split = Process.lookup('geo:splitPolygon')

Process inputs and metadata

Next define the process inputs and metadata. Enclose all of these definitions in a process block:

@process(

)

Add a title and description for better readability:

  title = 'Buffer and Split',
  description = 'Buffers a geometry and splits the resulting polygon.',

The process has three inputs as described above: a geometry (geom), a distance (dist) value to use when buffering the geometry, and a line (line) to use to split the subsequent geometry. Create the inputs list with these three definitions, along with a description:

  inputs = {
    'geom': (Geometry, 'The geometry to buffer'),
    'dist': (float, 'The distance by which to buffer the target geometry'),
    'line': (LineString, 'The line used for splitting the buffered geometry')
  },

The single output (result) will return a geometry, and is defined similarly:

  outputs = {
    'result': (Geometry, 'The buffered and split geometry')
  }

Process computation

Now that the inputs and outputs are defined, next create the computation through a function called run. This function has only two steps. The first step buffers the geom by the dist value, and the result is stored in the buffered variable. The second step splits the buffered geometry by the line. The final geometry is then returned.

def run(geom, dist, line):

  buffered = buffer.run(geom=geom, distance=dist)['result']
  return split.run(polygon=buffered, line=line)['result']

Activating the script

After the script is written, it must be added to GeoServer. Place the script in the GeoServer data directory in the location: <data_dir>/scripts/wps/. (Create this path if it doesn’t already exist.) The script will be activated automatically when copied to that location, with no server restart necessary.

Testing the script

Once the script is in place and activated, the next step is to test it. Use the WPS Request Builder in the GeoServer UI to verify this script’s functionality.

  1. Access the WPS Request Builder in the GeoServer UI by clicking on Demos then WPS Request Builder.

    ../../_images/demos.png
    ../../_images/requestbuilder.png

    Accessing the WPS Request Builder

  2. Select the process in the menu. It will be named py:bufferSplit.

    ../../_images/processcomposite_list.png

    Scripts listed as WPS processes

  3. Fill out the form. The following values will work for testing:

    Input Value
    line LINESTRING(-4 0, 4 0)
    geom LINESTRING(0 -1, 0 1)
    dist 1

    Enter these values in the form, making sure to select sure to select TEXT and application/wkt as the source format for each input and output.

    ../../_images/processcomposite_line.png

    Input line

    ../../_images/processcomposite_geom.png

    Input geometry

    ../../_images/processcomposite_dist.png

    Input distance

    ../../_images/processcomposite_result.png

    Result format

  4. Click Execute process.

    Note

    If you are curious about what the actual process request looks like, click Generate XML from process inputs/outputs.

  5. The output will look something like this:

    GEOMETRYCOLLECTION
      (POLYGON ((1 0, 1 -1, 0.9807852804032304 -1.1950903220161282,
      0.9238795325112867 -1.3826834323650898, 0.8314696123025452 -1.5555702330196022,
      0.7071067811865476 -1.7071067811865475, 0.5555702330196023 -1.8314696123025453,
      0.3826834323650898 -1.9238795325112867, 0.1950903220161283 -1.9807852804032304,
      0.0000000000000001 -2, -0.1950903220161282 -1.9807852804032304,
      -0.3826834323650897 -1.9238795325112867, -0.555570233019602
      -1.8314696123025453, -0.7071067811865475 -1.7071067811865475,
      -0.8314696123025453 -1.5555702330196022, -0.9238795325112868
      -1.3826834323650894, -0.9807852804032305 -1.1950903220161277, -1 -1, -1 0, 1
      0)), POLYGON ((-1 1, -0.9807852804032304 1.1950903220161286,
      -0.9238795325112867 1.3826834323650898, -0.8314696123025453 1.5555702330196022,
      -0.7071067811865475 1.7071067811865475, -0.555570233019602 1.8314696123025453,
      -0.3826834323650897 1.9238795325112867, -0.1950903220161282 1.9807852804032304,
      0.0000000000000001 2, 0.1950903220161283 1.9807852804032304, 0.3826834323650898
      1.9238795325112867, 0.5555702330196021 1.8314696123025453, 0.7071067811865476
      1.7071067811865475, 0.8314696123025453 1.5555702330196022, 0.923879532511287
      1.3826834323650894, 0.9807852804032305 1.1950903220161275, 1 1, 1 0, -1 0, -1
      1)))
    

    Or, graphically:

    ../../_images/processcomposite_example.png

    Buffer and Split example

    Note

    The curved nature of the output geometry stems from the default values of the geo:buffer inputs capStyle and quadrantSegments, which are set to Round and 8, respectively. These values can be explicitly set in the script, either by hard coding the values in the process call, or by adding new inputs to the process.