Changeset 807
- Timestamp:
- 05/15/07 02:16:20 (2 years ago)
- Files:
-
- Geographer/trunk/configure.zcml (modified) (2 diffs)
- Geographer/trunk/geo.py (modified) (1 diff)
- Geographer/trunk/interfaces.py (modified) (7 diffs)
- Geographer/trunk/tests/adapters.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
Geographer/trunk/configure.zcml
r745 r807 4 4 > 5 5 6 <adapter 7 for=".interfaces.IGeoreferenceable" 8 provides=".interfaces.IGeoItemSimple" 9 factory=".geo.GeoItemSimple" 6 <utility 7 component=".geo.geometryFactory" 8 name="geographer.Geometry" 10 9 /> 11 10 12 <adapter 13 for=".interfaces.IGeoserializable" 14 provides=".interfaces.IGeoCollectionSimple" 15 factory=".geo.GeoCollectionSimple" 16 /> 17 11 <adapter factory=".geo.GeoContentSimple"/> 18 12 19 13 <five:implements … … 22 16 /> 23 17 24 <five:implements25 class="Products.ATContentTypes.content.base.BaseContent"26 interface=".interfaces.IGeoserializable"27 />28 29 <five:implements30 class="Products.ATContentTypes.content.folder.ATFolder"31 interface=".interfaces.IGeoserializable"32 />33 34 <five:implements35 class="Products.ATContentTypes.content.topic.ATTopic"36 interface=".interfaces.IGeoserializable"37 />38 39 <include package=".browser"/>40 41 18 </configure> 42 19 Geographer/trunk/geo.py
r804 r807 28 28 # =========================================================================== 29 29 30 from zope.component import adapts, createObject 31 from zope.component.factory import Factory 30 32 from zope.interface import implements 31 from zope.app.annotation.interfaces import IAnnotations 32 from persistent.dict import PersistentDict 33 from zope.schema.fieldproperty import FieldProperty 33 34 34 from Products.ATContentTypes.interface.topic import IATTopic 35 from Products.ATContentTypes.interface.folder import IATFolder 35 try: 36 from zope.annotation.interfaces import IAnnotations 37 # For Zope 2 38 except: 39 from zope.app.annotation.interfaces import IAnnotations 36 40 37 from Products.Geographer.interfaces \ 38 import IGeoreferenceable, IGeoserializable, \ 39 IGeoItemSimple, IGeoCollectionSimple 41 from Products.Geographer.interfaces import IGeometry, IGeoItemSimple 42 from Products.Geographer.interfaces import IGeoreferenceable 40 43 41 ANNO_KEY = 'geocoder.simple.item'42 44 43 class GeoItemSimple(object): 44 45 """Python expression of a GeoRSS simple item. 45 # Geometry class and factory 46 47 class Geometry(object): 48 49 """A simple geometry. 50 """ 51 implements(IGeometry) 52 53 type = FieldProperty(IGeometry['type']) 54 coordinates = FieldProperty(IGeometry['coordinates']) 55 crs = FieldProperty(IGeometry['crs']) 56 57 58 geometryFactory = Factory( 59 Geometry, 60 title=u'Create a new geometry property', 61 ) 62 63 64 # Geo-referenced item 65 66 ANNO_KEY = 'geographer.geoitem' 67 68 class GeoContentSimple(object): 69 70 """Provides geo-referencing annotation and the Python feature protocol. 71 72 Useful for AT content types, could serve as a template for Zope 3 content 73 types. 46 74 """ 47 75 implements(IGeoItemSimple) 48 76 adapts(IGeoreferenceable) 77 49 78 def __init__(self, context): 50 79 """Initialize adapter.""" 51 80 self.context = context 52 81 annotations = IAnnotations(context) 53 self.georef = annotations.get(ANNO_KEY, None) 54 if not self.georef: 55 annotations[ANNO_KEY] = PersistentDict() 56 self.georef = annotations[ANNO_KEY] 57 self.georef['srs'] = 'EPSG:4326' 58 self.georef['geometryType'] = None 59 self.georef['spatialCoordinates'] = None 82 self.geometry = annotations.get(ANNO_KEY) 83 if not self.geometry: 84 annotations[ANNO_KEY] = createObject(u'geographer.Geometry') 85 self.geometry = annotations[ANNO_KEY] 86 self.geometry.type = 'Point' 87 self.geometry.coordinates = () 60 88 61 def getSRS(self): 62 return self.georef['srs'] 89 def getInfo(self): 90 context = self.context 91 title = context.Title() 92 description = context.Description() 63 93 64 def setSRS(self, srs): 65 try: 66 assert (srs.startswith('EPSG') or srs.find('proj') >= 0) 67 except AssertionError: 68 raise ValueError, \ 69 "%s is invalid. Spatial reference system definition must be in EPSG or PROJ.4 form" % (srs) 70 self.georef['srs'] = srs 71 72 def getGeometryType(self): 73 return self.georef['geometryType'] 94 return { 95 'id': context.getId(), 96 'properties': { 97 'title': unicode(title), 98 'description': unicode(description), 99 'uri': context.absolute_url(), 100 }, 101 'geometry': { 102 'type': self.geometry.type, 103 'coordinates': self.geometry.coordinates, 104 } 105 } 74 106 75 def setGeometryType(self, geomtype): 76 if geomtype not in ['point', 'line', 'polygon', 'box']: 77 raise ValueError, \ 78 """%s is invalid. Supported geometry types are: 'point', 'line', 'polygon', 'box'""" % (geomtype) 79 self.georef['geometryType'] = geomtype 107 info = property(getInfo,) 80 108 81 def getSpatialCoordinates(self):82 values = [float(v) for v in self.georef['spatialCoordinates'].split()]83 nvalues = len(values)84 npoints = nvalues/385 coords = []86 for i in range(npoints):87 coords.append(tuple(values[3*i:3*i+3]))88 return tuple(coords)89 90 def setGeometry(self, geomtype, coords):91 # set geometry type92 if geomtype not in ['point', 'line', 'polygon', 'box']:93 raise ValueError, \94 """%s is invalid. Supported geometry types are: 'point', 'line', 'polygon', 'box'""" % (geomtype)95 self.georef['geometryType'] = geomtype96 97 # check number of points against geometry type98 try:99 if geomtype == 'point': assert len(coords) == 1100 if geomtype == 'line': assert len(coords) >= 2101 if geomtype == 'polygon': assert len(coords) >= 4102 if geomtype == 'box': assert len(coords) == 2103 except AssertionError:104 raise ValueError, \105 "Number of coordinates %d is inconsistent with geometry type %s" \106 % (len(coords), geomtype)107 108 value = ''109 for point in coords:110 if len(point) == 3:111 value = ' '.join([value, "%f %f %f" % point])112 elif len(point) == 2:113 value = ' '.join([value, "%f %f 0.0" % point])114 else:115 raise ValueError, \116 "Insufficient number of ordinates: %s" % str(point)117 self.georef['spatialCoordinates'] = value.lstrip()118 119 def isGeoreferenced(self):120 """Return True if the object is "on the map"."""121 g = self.georef122 return bool(g['geometryType']) and bool(g['spatialCoordinates'])123 124 def getInfo(self, dims=3):125 """Return an informative dict."""126 g = self.georef127 context = self.context128 info = {'srs': g['srs'],129 'geometryType': g['geometryType']130 }131 if dims == 3:132 info['spatialCoordinates'] = g['spatialCoordinates']133 elif dims == 2:134 values = g['spatialCoordinates'].split()135 nvalues = len(values)136 npoints = nvalues/3137 coords = []138 for i in range(npoints):139 coords.extend(values[3*i:3*i+2])140 info['spatialCoordinates'] = ' '.join(coords)141 else:142 raise ValueError, "Invalid dims: %d" % (dims)143 144 # Content objects145 info.update(146 {'id': context.getId(),147 'title': context.title_or_id(),148 'description': context.getProperty('description',149 'No description'),150 'url': context.absolute_url(),}151 )152 return info153 154 155 class GeoCollectionSimple(object):156 157 """Adapter for Folderish collections of GeoItemSimple.158 """159 implements(IGeoCollectionSimple)160 161 def __init__(self, context):162 """Initialize."""163 self.context = context164 165 def geoItems(self):166 if IATTopic.providedBy(self.context):167 for ob in self.context.queryCatalog():168 try:169 item = IGeoItemSimple(ob.getObject())170 assert(item.isGeoreferenced())171 except:172 continue173 yield item174 elif IATFolder.providedBy(self.context):175 for ob in self.context.listFolderContents():176 try:177 item = IGeoItemSimple(ob)178 assert(item.isGeoreferenced())179 except:180 continue181 yield item182 else:183 try:184 item = IGeoItemSimple(self.context)185 assert(item.isGeoreferenced())186 except:187 pass188 yield item189 190 def getItemsInfo(self):191 infos = []192 for item in self.geoItems():193 infos.append(item.getInfo())194 return infos195 196 def getBoundingBox(self):197 raise NotImplementedError198 Geographer/trunk/interfaces.py
r806 r807 32 32 # For Zope 2 33 33 except ImportError: 34 from zope.a nnotation.interfaces import IAttributeAnnotatable34 from zope.app.annotation.interfaces import IAttributeAnnotatable 35 35 36 from zope.dublincore.interfaces import IDCDescriptiveProperties 37 36 38 from zope.interface import Interface 37 from zope.schema import Choice, Dict, Id, Object, TextLine, Tuple39 from zope.schema import BytesLine, Choice, Dict, Id, Object, Tuple, URI 38 40 39 41 # Marker interfaces. These are on the "for" side of a Zope3 adapter. … … 62 64 # Interfaces to be provided by adapters. 63 65 64 class IGeometry Property(Interface):66 class IGeometry(Interface): 65 67 66 68 """A geometry property with a geographic or projected coordinate system. … … 71 73 # TODO: geometries other than points 72 74 type = Choice( 73 values=("Point" ),75 values=("Point",), 74 76 title=u"Geometry Type", 75 77 description=u"The name of the geometry type. See " 76 78 "http://code.google.com/apis/kml/documentation/kml_tags_21.html", 77 required=True, 79 required=False, 80 default="Point", 78 81 ) 79 82 … … 81 84 title=u"Geometry Coordinates", 82 85 description=u"A sequence of coordinate tuples", 83 required=True,84 86 value_type=Tuple(title=u"Coordinates"), 87 required=False, 88 default=(), 85 89 ) 86 90 87 crs = TextLine(91 crs = BytesLine( 88 92 title=u"Coordinate Reference System", 89 93 description=u"The PROJ.4 format definition of a coordinate reference " 90 94 "system", 91 95 required=False, 92 default= u"epsg:4326",96 default="epsg:4326", 93 97 ) 94 98 95 99 96 class IGeoItemSimple(I nterface):100 class IGeoItemSimple(IDCDescriptiveProperties): 97 101 98 102 """A simple georeferenced object, analogous to an item in GeoRSS, or a … … 101 105 See http://georss.org/simple.html for an explanation of the simple GeoRSS 102 106 profile. 107 108 IDCDescriptiveProperties defines 'title' and 'description'. 103 109 """ 104 110 … … 109 115 ) 110 116 111 properties = Dict(112 title=u" Item Properties",113 description=u" Non-geometry properties and metadata",117 uri = URI( 118 title=u"URI", 119 description=u"Uniform Resource Identifier", 114 120 required=False, 115 default={},116 121 ) 117 122 118 123 geometry = Object( 119 IGeometry Property,124 IGeometry, 120 125 title=u"Geometry", 121 126 description=u"The item's geometry", … … 124 129 ) 125 130 126 131 info = Dict( 132 title=u"Info Dictionary", 133 description=u"Dictionary which provides the Python feature protocol", 134 readonly=True, 135 ) 136 127 137 class IGeoCollectionSimple(Interface): 128 138 Geographer/trunk/tests/adapters.txt
r803 r807 1 Sanity check 1 Adapter tests 2 ============= 2 3 3 >>> bool(1) 4 True 4 >>> from Products.Geographer.interfaces import IGeoItemSimple 5 5 6 Target: an AT content object 7 ---------------------------- 8 9 Add a new document and geo-reference it 10 11 >>> self.folder.invokeFactory('Document', id='document', title=u'A Document', 12 ... description=u'This is a document') 13 'document' 14 >>> item = IGeoItemSimple(self.folder.document) 15 >>> item 16 <Products.Geographer.geo.GeoContentSimple object at ...> 17 18 Set geometry properties 19 20 >>> item.geometry.type = 'Point' 21 >>> item.geometry.coordinates = ((0.0, 0.0, 0.0),) 22 23 Check info 24 25 >>> item.info 26 {'geometry': {'type': 'Point', 'coordinates': ((0.0, 0.0, 0.0),)}, 'id': 'document', 'properties': {'uri': 'http://nohost/plone/Members/test_user_1_/document', 'description': u'This is a document', 'title': u'A Document'}} 27
