Geometry processing functions
centroid
Arguments: [Geom]
Returns: Point
Implements centroid geometric function as per https://docs.geoserver.org/latest/en/user/filter/function_reference.html#geometric-functions
intersection
Arguments: [Geom, Geom]
Returns: Geom
intersection
bounds
Arguments: [relation: Relation[{}]]
Returns: Geom
Returns a polygon containing the spatial bounds (extent) of the given relation or coverage. The returned bounds may be used with other geometry functions, e.g intersects(exposure, bounds(bookmark('my-hazard')))
would return true for each exposure that has some intersection with the my-hazard
layer’s spatial extent.
The spatial bounds is a rectangular box that is the smallest size to cover all of the geometries. For further information see https://en.wikipedia.org/wiki/Minimum_bounding_box
buffer
Arguments: [geom: Geom, distance: Floating, options: {cap=>WithinSet(type=Text, allowed=[square, round, flat]), vertex=>WithinSet(type=Text, allowed=[round, mitre, bevel])}]
Returns: Geom
Buffer (or enlarge) a geometry by a given distance in metres. By default, buffering has the effect of rounding off corners and line endings in the original geometry, but this can be customized with the optional options
argument.
options.vertex' affects how external corners are enlarged. Given a 90 degree corner, like on a square,
round(the default) will round it off,
mitrewill preserve the same sharp corners as the original,
bevel` will cut a 45 degree line across the corner.
options.cap
affects how the end of a line is capped off. round
(the default) will round it off, square
will push the ends of the line outward but the end will be square, flat
is similar to square
but will not make the line longer.
Note that options.vertex
will not have any effect on line endings - only options.cap
will. Also note that using a flat
cap when buffering a point will result in an empty polygon.
create_point
Arguments: [Floating, Floating]
Returns: Point
Creates a geometry point using the given x, y coordinate
geom_from_wkt
Arguments: [wkt_text: Text]
Returns: Geom
Create a geometry object from a Well-Known Text (WKT) formatted geometry string, e.g. geom_from_wkt('POINT (1 2)')
. See https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry for more information about the well-known text format.
reproject
Arguments: [geom: Geom, crs: Text]
Returns: Geom
Reproject a geometry into another coordinate reference system (CRS). E.g to reproject to ‘EPSG:2193’ use reproject(geom, 'EPSG:2193')
.
Alternately the crs
argument may be another geometry. In this case the input geometry will be reprojected to the CRS that the other geometry is in. E.g reproject(geom, other_geom)
measure_area
Arguments: [geom: Geom]
Returns: Floating
Measure the area of geometry in metres squared (m²). Note that geometries that are specified in degrees are reprojected before being measured. This will lose accuracy for geometries that are larger than 6° in either direction and eventually fail if too big.
measure_length
Arguments: [geom: Geom]
Returns: Floating
Measure the length of a geometry’s perimeter in metres (m). Note that geometries that are specified in degrees are reprojected before being measured. This will lose accuracy for geometries that are larger than 6° in either direction and eventually fail if too big.
measure
Arguments: [geom: Geom]
Returns: Floating
Will measure either the length or area of a geometry, depending on its geometry type. Points will always return 0. Lines will return the length as per measure_length
. Polygon
‘s will return the area as per measure_area
. GeometryCollection
s will return the sum of all geometries in the collection
to_coverage
Arguments: [values: Relation[{}], options: Anything]
Returns: Coverage[Anything]
Produces a coverage from a collection of tuples. The values
argument is the data to turn into a coverage, and can be either a relation or a list of tuples. This function can also be used as an aggregate function to collect tuples (i.e. in a ‘group’ pipeline step).
The produced coverage can be sampled using one of the sampling functions (e.g. sample
, sample_centroid
or sample_one
). The coverage is constructed by adding all of the tuples into a spatial index, which is queried for matching tuples when sampled. The tuples in the coverage must contain a single geometry member that is spatially referenced.
There are two types of index that can be constructed, ‘intersection’ and ‘nearest_neighbour’, which can be specified by the index
option, e.g. to_coverage(values, options: {index: 'intersection'})
. The default index
is ‘intersection’.
The intersection
index is most appropriate for indexing polygonal features. The sampling operation will query the index for any intersecting features, and return those that match according to the semantics of the sampling operation that was used. Setting the option intersection_cut
to true can improve performance considerably when you intend to sample the index using either sample_one
or sample_centroid
. This has the most dramatic effect when the indexed features are large or irregular, at the cost of higher memory usage. For more advanced tuning options, refer to the IntersectionIndex
‘s source code.
The nearest_neighbour
index is best when indexing point features. A sampling operation will query the index for the nearest feature’s point (with a max distance cut off). Only sample_centroid
is currently supported for this type of index. The cutoff distance must be supplied as the nearest_neighbour_max_distance
option. E.g to use a nearest neighbour index with a cutoff of one kilometre use to_coverage(tuples, options: {index: 'nearest_neighbour', nearest_neighbour_max_distance: 1000})
The simplest example of using this function in a pipeline is with bookmark data (typically a relation), e.g. sample_centroid(building.geom, to_coverage(bookmark(‘hazard’))) Note that the above sampling operation will work regardless of whether the ‘hazard’ bookmark is vector data (i.e. a relation) or raster data (i.e. already a coverage).
sample
Arguments: [geometry: Geom, coverage: Coverage[Anything]]
Returns: List[{geometry=>Geom, sampled=>Anything}]
Selects all the values from a coverage that intersect with the given geometry.
This function is useful for determining details such as the total amount that a polygon or line-string is exposed to a hazard, or the specific min/mean/max/etc hazard intensity measure for a given feature.
The given geometry may intersect the coverage multiple times (e.g. multiple pixels in a GeoTIFF), and so a list of intersections is returned. Each list item contains a geometry
attribute, which is an intersecting piece of the input geometry, and a sampled
attribute, which is the value returned from the coverage at that specific location.
Note that when building a simple model, the sample_one
function might be easier to use instead, as that lets you work with a single sampled value instead of a list of values.
sample_centroid
Arguments: [geometry: Geom, coverage: Coverage[Anything]]
Returns: Anything
Select a single value from a coverage by sampling at the geometry’s centroid (centre point). This function will return null if there is no sample at the centroid even if there are samples that intersect other parts of the geometry.
sample_one
Arguments: [geometry: Geom, coverage: Coverage[Anything], buffer-distance: Floating]
Returns: Anything
Selects a single value from a coverage. If the geometry intersects with multiple values in the coverage then the value closest to the geometry centroid is chosen. If nothing is found and ‘buffer-distance’ is specified (in metres) then the geometry is buffered (enlarged) by that amount and the coverage is sampled again, but this time the value closest to the geometry is chosen.
Note: buffering is done with an estimated metric-to-map-unit distance, which can be inaccurate for degree (lat/long) based projections.
segment
Arguments: [geometry: Geom, distance: Floating]
Returns: List[Geom]
Cut geometries up by a distance specified in metres (m). Linestrings are cut into pieces of at most distance
metres in length. Polygons are cut using a grid - each grid cell is a square, where each side is distance
metres in length. E.g. cutting a polygon by 100m will result in grid cells that are 100m x 100m (10000m²) squares. The grid is aligned to each polygon’s centroid, so there is no guarantee that each segment will have a particular area. E.g. cutting a 10001m² polygon by 100m may result in four 2500.25m² segments.
segment_by_grid
Arguments: [geometry: Geom, distance: Floating, align-to: Anything]
Returns: List[Geom]
Cut geometries up by a grid that has a mesh size of distance specified in metres (m). The grid is aligned with the to-align
parameter which may be a point or a coverage (in which case the lower left corner is aligned to).
layer_intersection
Arguments: [feature: Anything, layer: Anything, merge_attributes: Nullable[Anything], return_difference: Nullable[Bool]]
Returns: List[{}]
Compute the intersection of a feature (a geometry-containing struct) with all of the features in another layer. The function returns a list of features that represent the intersection. If the function is given just two arguments, then the returned features are a copy of the original feature with just the geometry replaced by the intersection.
The third optional argument is a struct containing layer
attributes to merge into the result. The identifier of each struct member is the new name the attribute will be given in the result. For example, if the given argument was {area_name: 'name', soil_type: soil_type}
then this would merge in the soil_type
attribute from the given layer
, but rename the name
attribute as area_name
in the result.
The fourth optional return_difference
argument determines what parts of the original geometry are included in the result. If false
(the default), then only the geometry intersection is returned. If true
, the intersection as well as any difference (non-overlapping geometry) is returned.
combine_coverages
Arguments: [coverages: Anything, grid-resolution: Floating]
Returns: Coverage[{}]
Combines multiple coverages into one. This lets you sample multiple hazard or resource-layers with a single operation.
For example, combine_coverages({shaking: event.shakemap, soil_type: resource_layer}, 100)
would build a new coverage. Sampling the new coverage would return a struct. The attributes in this struct are the combined result of sampling the event.shakemap
and resource_layer
coverages respectively. The attributes names will be shaking
and soil_type
(or derivatives of these).
The first argument, coverages
, must be a { key: value, ... }
struct expression. Each value
in this struct expression must be a coverage. Each key
will be used for the attribute names in the result, when the combined coverage is sampled. If the individual coverage is raster data, the key name will be used exactly, e.g. shaking
. If the individual coverage is vector data, the key name will be used as a prefix, e.g. shaking_pga
. Note that the underlying vector-layer geometry is not returned at all.
The second grid-resolution
argument specifies a common grid-size, in metres, to use across all the coverages. When the combined coverage is sampled using non-point geometry, the input geometry will be cut up using the given grid-resolution
distance.
Cutting is done using the same method as the segment_by_grid()
function. The grid-resolution
should generally match the raster coverage with the smallest grid size.
Note that sampling intersections from a combined coverage only uses the centre point of each grid segment. Sampling may produce slightly different results at different grid-resolutions, especially when sampling a combined vector layer, and especially if the vector geometry is small, such as ballistics data.
Using a smaller grid-resolution
will provide better accuracy when sampling vector data. However, a smaller grid-resolution
will be much more processing intensive and make your model run slower.
map_coverage
Arguments: [coverage: Coverage[Anything], expression: λ(sampled)]
Returns: Coverage[Anything]
Applies an expression to transform the value(s) sampled from the given coverage. For example, this lets you convert the sampled value(s) from centimetres to metres, or from log-scale units to non-log units.
For example, to convert from centimetres to metres you would use: map_coverage(coverage, (x) -> x / 100)