/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/layer.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/layer.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1452 by bh, Fri Jul 18 12:57:59 2003 UTC revision 2343 by bernhard, Mon Sep 20 08:13:32 2004 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
5    # Silke Reimer <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
9    
10  __version__ = "$Revision$"  __version__ = "$Revision$"
11    
12  from math import log, ceil  import os
13  import warnings  import warnings
14    
15  from Thuban import _  from Thuban import _
 import shapelib, shptree  
16    
17  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
18       LAYER_CHANGED, LAYER_SHAPESTORE_REPLACED, CLASS_CHANGED       LAYER_CHANGED, LAYER_SHAPESTORE_REPLACED, CLASS_CHANGED
# Line 21  import classification Line 21  import classification
21    
22  from color import Transparent, Black  from color import Transparent, Black
23  from base import TitledObject, Modifiable  from base import TitledObject, Modifiable
24    from data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
25    
26  import resource  import resource
27    
28    
 class Shape:  
   
     """Represent one shape"""  
   
     def __init__(self, points):  
         self.points = points  
         #self.compute_bbox()  
         self.bbox = None  
   
     def compute_bbox(self):  
         if self.bbox is not None:  
             return self.bbox  
   
         xs = []  
         ys = []  
         for x, y in self.points:  
             xs.append(x)  
             ys.append(y)  
         self.llx = min(xs)  
         self.lly = min(ys)  
         self.urx = max(xs)  
         self.ury = max(ys)  
   
         self.bbox = (self.llx, self.lly, self.urx, self.ury)  
   
         return self.bbox  
   
     def Points(self):  
         return self.points  
   
   
   
 # Shape type constants  
 SHAPETYPE_POLYGON = "polygon"  
 SHAPETYPE_ARC = "arc"  
 SHAPETYPE_POINT = "point"  
   
 # mapping from shapelib shapetype constants to our constants  
 shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,  
                        shapelib.SHPT_ARC: SHAPETYPE_ARC,  
                        shapelib.SHPT_POINT: SHAPETYPE_POINT}  
   
29  shapetype_names = {SHAPETYPE_POINT: "Point",  shapetype_names = {SHAPETYPE_POINT: "Point",
30                     SHAPETYPE_ARC: "Arc",                     SHAPETYPE_ARC: "Arc",
31                     SHAPETYPE_POLYGON: "Polygon"}                     SHAPETYPE_POLYGON: "Polygon"}
# Line 96  class BaseLayer(TitledObject, Modifiable Line 55  class BaseLayer(TitledObject, Modifiable
55          self.issue(LAYER_VISIBILITY_CHANGED, self)          self.issue(LAYER_VISIBILITY_CHANGED, self)
56    
57      def HasClassification(self):      def HasClassification(self):
58          """Determine if this layer support classifications."""          """Determine if this layer supports classifications."""
59          return False          return False
60    
61      def HasShapes(self):      def HasShapes(self):
# Line 108  class BaseLayer(TitledObject, Modifiable Line 67  class BaseLayer(TitledObject, Modifiable
67          return self.projection          return self.projection
68    
69      def SetProjection(self, projection):      def SetProjection(self, projection):
70          """Set the layer's projection"""          """Set the layer's projection."""
71          self.projection = projection          self.projection = projection
72          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
73    
# Line 167  class Layer(BaseLayer): Line 126  class Layer(BaseLayer):
126    
127          self.UnsetModified()          self.UnsetModified()
128    
     def __getattr__(self, attr):  
         """Access to some attributes for backwards compatibility  
   
         The attributes implemented here are now held by the shapestore  
         if at all. For backwards compatibility pretend that they are  
         still there but issue a DeprecationWarning when they are  
         accessed.  
         """  
         if attr in ("table", "shapetable"):  
             value = self.store.Table()  
         elif attr == "shapefile":  
             value = self.store.Shapefile()  
         elif attr == "filename":  
             value = self.store.FileName()  
         else:  
             raise AttributeError, attr  
         warnings.warn("The Layer attribute %r is deprecated."  
                       " It's value can be accessed through the shapestore"  
                       % attr, DeprecationWarning, stacklevel = 2)  
         return value  
   
129      def SetShapeStore(self, store):      def SetShapeStore(self, store):
130          # Set the classification to None if there is a classification          # Set the classification to None if there is a classification
131          # and the new shapestore doesn't have a table with a suitable          # and the new shapestore doesn't have a table with a suitable
# Line 204  class Layer(BaseLayer): Line 142  class Layer(BaseLayer):
142                  self.SetClassification(None)                  self.SetClassification(None)
143    
144          self.store = store          self.store = store
         shapefile = self.store.Shapefile()  
145    
         numshapes, shapetype, mins, maxs = shapefile.info()  
         self.numshapes = numshapes  
         self.shapetype = shapelib_shapetypes[shapetype]  
   
         # if there are shapes, set the bbox accordingly. Otherwise  
         # set it to None.  
         if self.numshapes:  
             self.bbox = mins[:2] + maxs[:2]  
         else:  
             self.bbox = None  
   
         # estimate a good depth for the quad tree. Each depth  
         # multiplies the number of nodes by four, therefore we  
         # basically take the base 4 logarithm of the number of  
         # shapes.  
         if self.numshapes < 4:  
             maxdepth = 1  
         else:  
             maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))  
   
         self.shapetree = shptree.SHPTree(shapefile.cobject(), 2,  
                                          maxdepth)  
146          self.changed(LAYER_SHAPESTORE_REPLACED, self)          self.changed(LAYER_SHAPESTORE_REPLACED, self)
147    
148      def ShapeStore(self):      def ShapeStore(self):
# Line 244  class Layer(BaseLayer): Line 159  class Layer(BaseLayer):
159    
160          If the layer has no shapes, return None.          If the layer has no shapes, return None.
161          """          """
162          return self.bbox          return self.store.BoundingBox()
163    
164      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
165          """Return the layer's bounding box in lat/long coordinates.          """Return the layer's bounding box in lat/long coordinates.
# Line 252  class Layer(BaseLayer): Line 167  class Layer(BaseLayer):
167          Return None, if the layer doesn't contain any shapes.          Return None, if the layer doesn't contain any shapes.
168          """          """
169          bbox = self.BoundingBox()          bbox = self.BoundingBox()
170          if bbox is not None:          if bbox is not None and self.projection is not None:
171              llx, lly, urx, ury = bbox              bbox = self.projection.InverseBBox(bbox)
172              if self.projection is not None:          return bbox
                 llx, lly = self.projection.Inverse(llx, lly)  
                 urx, ury = self.projection.Inverse(urx, ury)  
             return llx, lly, urx, ury  
         else:  
             return None  
173    
174      def ShapesBoundingBox(self, shapes):      def ShapesBoundingBox(self, shapes):
175          """Return a bounding box in lat/long coordinates for the given          """Return a bounding box in lat/long coordinates for the given
# Line 270  class Layer(BaseLayer): Line 180  class Layer(BaseLayer):
180    
181          if shapes is None or len(shapes) == 0: return None          if shapes is None or len(shapes) == 0: return None
182    
183          llx = []          xs = []
184          lly = []          ys = []
         urx = []  
         ury = []  
   
         if self.projection is not None:  
             inverse = lambda x, y: self.projection.Inverse(x, y)  
         else:  
             inverse = lambda x, y: (x, y)  
185    
186          for id in shapes:          for id in shapes:
187              left, bottom, right, top = self.Shape(id).compute_bbox()              bbox = self.Shape(id).compute_bbox()
188                if self.projection is not None:
189              left, bottom = inverse(left, bottom)                  bbox = self.projection.InverseBBox(bbox)
190              right, top   = inverse(right, top)              left, bottom, right, top = bbox
191                xs.append(left); xs.append(right)
192                ys.append(bottom); ys.append(top)
193    
194              llx.append(left)          return (min(xs), min(ys), max(xs), max(ys))
             lly.append(bottom)  
             urx.append(right)  
             ury.append(top)  
195    
         return (min(llx), min(lly), max(urx), max(ury))  
196    
197      def GetFieldType(self, fieldName):      def GetFieldType(self, fieldName):
198          if self.store:          if self.store:
# Line 305  class Layer(BaseLayer): Line 206  class Layer(BaseLayer):
206    
207      def NumShapes(self):      def NumShapes(self):
208          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
209          return self.numshapes          return self.store.NumShapes()
210    
211      def ShapeType(self):      def ShapeType(self):
212          """Return the type of the shapes in the layer.          """Return the type of the shapes in the layer.
213          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.  
214            The return value is one of the SHAPETYPE_* constants defined in
215            Thuban.Model.data.
216          """          """
217          return self.shapetype          return self.store.ShapeType()
218    
219      def Shape(self, index):      def Shape(self, index):
220          """Return the shape with index index"""          """Return the shape with index index"""
221          shape = self.store.Shapefile().read_object(index)          return self.store.Shape(index)
   
         if self.shapetype == SHAPETYPE_POINT:  
             points = shape.vertices()  
         else:  
             #for poly in shape.vertices():  
             poly = shape.vertices()[0]  
             points = []  
             for x, y in poly:  
                 points.append((x, y))  
222    
223          return Shape(points)      def ShapesInRegion(self, bbox):
224            """Return an iterable over the shapes that overlap the bounding box.
225    
226      def ShapesInRegion(self, box):          The bbox parameter should be the bounding box as a tuple in the
227          """Return the ids of the shapes that overlap the box.          form (minx, miny, maxx, maxy) in unprojected coordinates.
   
         Box is a tuple (left, bottom, right, top) in unprojected coordinates.  
228          """          """
         left, bottom, right, top = box  
   
229          if self.projection is not None:          if self.projection is not None:
230              left,  bottom = self.projection.Forward(left, bottom)              # Ensure that region lies within the layer's bounding box
231              right, top    = self.projection.Forward(right, top)              # Otherwise projection of the region would lead to incorrect
232                # values.
233          return self.shapetree.find_shapes((left, bottom), (right, top))              clipbbox = self.ClipBoundingBox(bbox)
234                bbox = self.projection.ForwardBBox(clipbbox)
235            return self.store.ShapesInRegion(bbox)
236    
237      def GetClassificationColumn(self):      def GetClassificationColumn(self):
238          return self.classification_column          return self.classification_column
# Line 401  class Layer(BaseLayer): Line 294  class Layer(BaseLayer):
294    
295          bbox = self.LatLongBoundingBox()          bbox = self.LatLongBoundingBox()
296          if bbox is not None:          if bbox is not None:
297              items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)              items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % tuple(bbox))
298          else:          else:
299              items.append(_("Extent (lat-lon):"))              items.append(_("Extent (lat-lon):"))
300          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
# Line 414  class Layer(BaseLayer): Line 307  class Layer(BaseLayer):
307    
308          return (_("Layer '%s'") % self.Title(), items)          return (_("Layer '%s'") % self.Title(), items)
309    
310        def ClipBoundingBox(self, bbox):
311            """ Clip bbox to layer's bounding box.
312    
313            Returns that part of bbox that lies within the layers bounding box.
314            If bbox is completely outside of the layers bounding box, bbox is
315            returned.  It is assumed that bbox has sensible values, i.e. bminx
316            < bmaxx and bminy < bmaxy.
317            """
318            bminx, bminy, bmaxx, bmaxy = bbox
319            lminx, lminy, lmaxx, lmaxy = self.LatLongBoundingBox()
320            if bminx > lmaxx or bmaxx < lminx:
321                left, right = bminx, bmaxx
322            else:
323                left = max(lminx, bminx)
324                right = min(lmaxx, bmaxx)
325            if bminy > lmaxy or bmaxy < lminy:
326                bottom, top = bminy, bmaxy
327            else:
328                bottom = max(lminy, bminy)
329                top = min(lmaxy, bmaxy)
330            
331            return (left, bottom, right, top)
332    
333    
334  if resource.has_gdal_support():  if resource.has_gdal_support():
335      import gdal      import gdal
# Line 440  class RasterLayer(BaseLayer): Line 356  class RasterLayer(BaseLayer):
356          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title, visible = visible)
357    
358          self.projection = projection          self.projection = projection
359          self.filename = filename          self.filename = os.path.abspath(filename)
360    
361          self.bbox = -1          self.bbox = -1
362    
# Line 502  class RasterLayer(BaseLayer): Line 418  class RasterLayer(BaseLayer):
418          if bbox is None:          if bbox is None:
419              return None              return None
420    
         llx, lly, urx, ury = bbox  
421          if self.projection is not None:          if self.projection is not None:
422              llx, lly = self.projection.Inverse(llx, lly)              bbox = self.projection.InverseBBox(bbox)
             urx, ury = self.projection.Inverse(urx, ury)  
423    
424          return llx, lly, urx, ury          return bbox
425    
426      def GetImageFilename(self):      def GetImageFilename(self):
427          return self.filename          return self.filename

Legend:
Removed from v.1452  
changed lines
  Added in v.2343

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26