Making existing AT objects IGeoAware
This document describes how developers may take existing ArcheTypes content types and with few lines of code extend them to implement the IGeoAware interface thus making them usable as spatial data for PrimaGIS. The GeoATImage object from the GeoAwareObjects product is used as an example.
IGeoAware interface
The IGeoAware interface defines four methods objects must implement
in order to be usable with PrimaGIS:
- getGeometry
- getGeoTitle
- getGeoDescription
- getGeoURL
Each method is documented in the IGeoAware interface defined in
interfaces.py file within the PrimaGIS product. The most important method is
getGeometry, which must return a PCL geometry object (which are defined in the cartography.spatial module) representing the
spatial data. Depending on your needs the geometry object may represent either
POINT, LINESTRING or POLYGON geometries. The other three methods should return
metadata about the object that will be shown and used in the popup
windows.
GeoAwareMixin
The most straight-forward method for spatially extending existing AT
objects would be to make your own product extend the AT object and then
implement the four methods mentioned above by hand. In order to help
developers implement the IGeoAware interface, the PrimaGIS.GeoAwareMixin
module defines mixin classes and schemas for each type of geometry that your
own products may inherit. This will reduce the amount of code you have to
write unless your needs are very specific.
GeoATImage - a spatially enabled ATImage
GeoATImage from the GeoAwareObjects product is a simple content type that extends the ATImage object from ATContentTypes making it usable with PrimaGIS. This allows you to show images within the popup windows on the map. The source code for GeoATImage is shown below
from Products.PrimaGIS.interfaces import IGeoAware
from Products.PrimaGIS.GeoAwareMixin import PointMixinSchema, PointMixin
from Products.ATContentTypes.types import ATImage
from Products.Archetypes.public import registerType
from AccessControl import ClassSecurityInfo
from Products.GeoAwareObjects.config import PROJECTNAME
class GeoATImage(ATImage.ATImage, PointMixin):
"""
This class extends the ATImage from ATContentTypes with methods
that implement the IGeoAware interface which allows the images
to rendered on the map as ECMAScript popups.
"""
__implements__ = IGeoAware,
schema = ATImage.ATImage.schema.copy() + PointMixinSchema
security = ClassSecurityInfo()
meta_type = 'GeoATImage'
archetype_name = 'Geo-aware AT Image'
## IGeoAware implementation
security.declarePublic('getGeoDescription')
def getGeoDescription(self):
"""
Return the XHTML image tag to render the image in the
popup window.
This method overrides the PointMixin.getGeoDescription() method.
"""
return self.tag()
registerType(GeoATImage, PROJECTNAME)
The implementation is quite trivial. The important part is that our
new content type inherits both the existing AT content type and a mixin
class from PrimaGIS.GeoAwareMixin. In this particular case it is
natural to use the POINT geometry and thus we inherit from
GeoAwareMixin.PointMixin. In the same way we set the schema for our new
content type to contain both the original ATImage schema and a
GeoAwareMixin.PointMixinSchema.
At this point we already have a working, spatially enabled derivate
of ATImage. Inheriting PointMixin automatically implements the
IGeoAware interface making GeoATImage to be usable with PrimaGIS.
Because we wish to have the image represented by GeoATImage to rendered
in the popup window, we must override the getGeoDescription() method in
order to achieve this. Having the new getGeoDescription() method return
the image tag will accomplish this.
At this point we have a new derived content type that allows us to
render images on PrimaGIS maps and we have achieved this with only few
lines of code.
Discussion
This article showed us how to spatially extend existing AT objects. It may not be always feasible to create a new content type only to have it made usable with PrimaGIS. The GeoArchetypesProxy allows using arbitrary AT objects as data for the maps without having to modify them or create new content types. The GeoArchetypesProxy objects implement the IGeoAware interface and store the spatial data within them and simply refer to the corresponding AT objects.
The proxy approach is somewhat limited and currently supports only POINT geometries and by default renders the Dublin Core Description field in the popup window. In this particular case we needed to modify that behaviour to render the image instead and opted to create a new derived content type.
The mixin classes and schemas defined in GeoAwareMixin module aim to be very general and if you have very specific or complex needs then implementing IGeoAware by hand is recommended.