Map data and display classes
----------------------------

The ``gt-render`` module defines a new data structure to represent the contents of a map. ``MapContent``
defines a map as a series of layers (which are drawn in order). This is not part of the formal
``gt-opengis`` module because it is not based on a standard.

MapContent
^^^^^^^^^^

``MapContent`` is used to capture the contents of a map for rendering.

.. image:: /images/map_content.PNG

These ideas are broken down into the following three classes:

* ``MapContent``
  
  The contents of a map to be drawn.

* ``MapViewport``
  
  Represents the area of the map to drawn. The viewport stores:
 
  * the world bounds (spatial extent in world units) of the area to be drawn;
  * the screen, image or device bounds to draw into;
  * the coordinate transforms used to convert between world and screen positions.

  In practice, you provide the world and screen bounds to a ``MapViewport`` object and
  it calculates the coordinate transforms for you (see :ref:`aspect-ratio` for more details).

  Potentially, a viewport could also work with parameters other than horizontal spatial extent when
  defining the map data to be drawn such as height or time. The ``MapViewport`` class does not presently
  support such usage but you could derive a sub-class for this purpose.
  
* ``Layer`` - represents a layer of content to be drawn; layers are held in a list and are drawn in
  order.

Examples:

* Direct access to layer information is provided::
  
    MapContent content = mapFrame.getMapContent();
    if( content.layers().get(0) instanceof FeatureLayer ){
        FeatureLayer selectionLayer = (FeatureLayer) content.layers().get(0);
        selectLayer.setStyle( style );
    }

* Zoom out to show all content::
    
        MapContent content = mapFrame.getMapContent();
        MapViewport viewport = content.getMapViewport();
        ReferencedEnvelope maxBounds = null;
        CoordinateReferenceSystem mapCRS = viewport.getCoordinateReferenceSystem();
        
        for (Layer layer : content.layers()) {
            ReferencedEnvelope dataBounds = layer.getBounds();
            CoordinateReferenceSystem dataCrs = dataBounds.getCoordinateReferenceSystem();
            if (!CRS.equalsIgnoreMetadata(dataCrs, mapCRS)) {
                dataBounds = dataBounds.transform(mapCRS, true);
            }
            if (maxBounds == null) {
                maxBounds = dataBounds;
            } else {
                maxBounds.expandToInclude(dataBounds);
            }
        }
        viewport.setBounds( maxBounds );


.. _aspect-ratio:

Aspect-ratio of map and screen bounds
'''''''''''''''''''''''''''''''''''''

Very often, the aspect ratio (ratio of width to height) of the world and screen bounds will differ.
By default, ``MapViewport`` does not make any correction for this (this behavior accords with the OGC
WMS specification which states that a map server should honor the bounds provided by the user
regardless of any distortion which results).

In many cases, it is preferable to have ``MapViewport`` automatically correct for differing aspect
ratios, thereby avoiding distortion in the map display. You can request this behavior as follows::

    MapViewport vp = myMapContent.getViewport();
    vp.setMatchingAspectRatio( true );

With this setting, the viewport will calculate coordinate transforms such that the user requested
world bounds are centered in the screen or image display area. Note that when such a correction has
been applied, the world bounds stored by the viewport will be larger than those requested by the
user.

Layer
^^^^^

We have different subclasses of of ``Layer`` each specifically made for working with different kinds
of content.

.. image:: /images/layer.PNG

The important information each ``Layer`` implementation must provided is:

* ``Layer.getTitle()``
* ``Layer.setTitle( String )``
  
  Used in a legend to display to the user
* ``Layer.isVisible()``
* ``Layer.setVisible( boolean )``
* ``Layer.getuserData()``
  
  A general purpose map used by applications to hold information. This
  approach was preferred as an alternative to loading up ``Layer`` with additional methods to
  handle selection, error feedback and so forth.
* ``Layer.getBounds()`` - the extent of the data being rendered by the ``Layer``
* ``Layer.addMapLayerListener()``
* ``Layer.removeMapLayerListener()``
  
  Used to notify the renderer of any changes when used in an interactive setting.

With these ideas in mind we can now explore the different kinds of content that can be added
to a map:
  
FeatureLayer
''''''''''''

``FeatureLayer`` is set up to render information from a ``FeatureSource``.
  
.. image:: /images/feature_layer.PNG
 
You can use the various method of the ``DataUtilities`` class to convert your information into
a ``FeatureSource`` if it happens to be in another format. This is what the constructor that
takes a ``FeatureCollection`` does internally.

GridCoverageLayer
'''''''''''''''''

Used to render a ``GridCoverage``.

.. image:: /images/gridcoverage_layer.PNG

Note that direct use of a ``GridCoverage`` in this fashion is generally not as efficient 
as using ``GridReaderLayer`` below.

GridReaderLayer
'''''''''''''''

Used to render raster information on the fly directly from a ``GridCoverageReader``.

.. image:: /images/gridreader_layer.PNG
  
This is an efficient solution (much like ``FeatureSource``) in that for many cases the correct visual
can be determined without reading all of the raster into memory:

* When zoomed in the amount of the file read can be limited when working with common formats
  such as GeoTiff. Other formats such as JPEG require that the entire image be loaded each time.
* When zoomed out information from a raster overlay can be used (if available) to avoid reading the
  entire file.

The performance of ``GridReaderLayer`` is dependent on how you have tuned your Java Advanced Imaging
``TileCache`` and on the amount of work you have put into preparing your data for display.

This class has been extended by ``gt-wms`` for the rendering of WMS information.

DirectLayer
'''''''''''

*Experimental*: ``DirectLayer`` is used fill in your own custom renderer (primarily intended for
drawing scale bars, north arrows and grids to decorate the map).
  
.. image:: /images/direct_layer.PNG
  
This concept is considered experimental and is not currently hooked up.
  
MapContext
^^^^^^^^^^

An earlier draft of these ideas is based on initial OGC discussion papers:
 
* Web Map Context (WMS Context)
* Open Web Service Context (OWS Context)

The GeoTools community actively looking to collaborate with other projects (such as OpenJUMP,
uDig and Deegree) in order to collaborate on these ideas. If open source collaboration fails
we will look to traditional collaboration with a standards body in the form of the
OGC working group on "Open Web Context" documents.
   
References:

* http://www.opengeospatial.org/standards/wmc
* http://www.opengeospatial.org/projects/groups/owscontextswg

These initial concepts are preserved with the following extensions to ``MapContent``.

.. image:: /images/map_context.PNG

The critical design difference here is a single *MapLayer* which is general purpose for working
with any kind of content (and also confusing to work with as their is no easy way to check what
kind of content is in use).

.. note::

  Internally this code has been refactored to use MapContent / Layer and MapViewport. As such we do
  not recommend using MapContext and MapLayer for new development.
  
  At a technical level we no longer keep instances of of MapLayer around; instead each is a
  shallow wrapper around a layer holding the specific content (FeatureLayer, GridReaderLayer,
  etc...).
  
  In the event client code is expecting a MapLayer; this wrapper is recreated as needed and
  returned from ``getLayer(int)`` method.
  
  In a similar fashion the various methods for managing the area of interest delegate to
  MapViewport.
