Introduction

This page provides some background of the concept of geometry transformations in SLD, a tool that can be used to improve the rendering abilities and address some commonly requested rendering abilities.

Rendering chain and transformations

The idea behind transformations is simple, instead of drawing the geometry directly we plan to support its transformation into a different geometry by means of a filter function declared in the SLD. For example:

<PointSymbolizer>
  <Geometry>
    <ogc:Function name="endPoint">
       <ogc:PropertyName>aLineGeometry</ogc:PropertyName>
    </ogc:Function>
  </Geometry>
  ...
</PointSymbolizer>

Considering the rendering pipeline there are two steps in which a transformation can be injected. Here is a list of the rendering steps with transformations embedded into them:

Both kinds of transformations are useful:

The SE 1.1 specification seems to address, via a finite set of transformations, both of them, depending on the unit of measure used in the symbolizer.
This proposal is about going beyond, and having a pluggable extension point for people to create whatever transformation they need.

Typical use cases

Geometry transformations can be used in a number of cases. Here are some example:

A tentative implementation

During the code sprint at FOSS4G 2009 a tentative geometry transformation implementation has been created that addresses only the first type of transformation, the one operating in real world coordinates.

The changes needed to support a simple version of it in the streaming renderer are not big, neither are those required in the parsing. Some API changes were needed so that Symbolizer.getGeometry() returns a generic Expression instead of a PropertyName.
The patch to trunk is attached to this page for review.

Besides the changes in the GeoTools Symbolizer interfaces the other new piece of API is the GeometryTransformation interface:

/**
 * This interface can be implemented by geometry transformation functions
 * that whish to be used in the {@link Symbolizer} geometry property.
 * <p>It gives the renderer a hint of what area should be queried given a certain rendering area
 * @author aaime
 *
 */
public interface GeometryTransformation extends Function {
    /**
     * Returns a query envelope given a certain 
     * @param renderingEnvelope
     * @return
     */
    ReferencedEnvelope invert(ReferencedEnvelope renderingEnvelope);
}

The interface should be implemented by all transformation that do change the location of the geometry during the transformation, and it's used by the renderer to guess the query area given the display area. For example, a buffer transformation will require an extended query area to catch those feature that are sitting out of the display area, but whose buffer crosses into the display area.
The renderer uses a visitor to get the full transformation (as transformations can be chained together, for example one could first perform an intersection and then buffer the result).

The patch attached also introduces samples of the above:

The patch also includes tests for the transformation machinery.

Looking into the future

The future of this work requires the implementation of more transformations and the ability to perform transformations in pixel space as well. This could be implemented, for example, by using a visitor that takes the transformation and wraps the geometry accesses within a further transformation that applies the generalization, reprojection and world to screen transformations.