/[thuban]/trunk/thuban/Thuban/Model/layer.py
ViewVC logotype

Diff of /trunk/thuban/Thuban/Model/layer.py

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

revision 725 by jonathan, Thu Apr 24 16:05:36 2003 UTC revision 1142 by bh, Tue Jun 10 09:41:57 2003 UTC
# Line 14  from Thuban import _ Line 14  from Thuban import _
14    
15  import shapelib, shptree  import shapelib, shptree
16    
17    import gdal
18    from gdalconst import GA_ReadOnly
19    
20  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
21       LAYER_CHANGED       LAYER_CHANGED, LAYER_SHAPESTORE_REPLACED
22    
23  from color import Color  from color import Color
24    
# Line 31  class Shape: Line 34  class Shape:
34      def __init__(self, points):      def __init__(self, points):
35          self.points = points          self.points = points
36          #self.compute_bbox()          #self.compute_bbox()
37            self.bbox = None
38    
39      def compute_bbox(self):      def compute_bbox(self):
40            if self.bbox is not None:
41                return self.bbox
42    
43          xs = []          xs = []
44          ys = []          ys = []
45          for x, y in self.points:          for x, y in self.points:
# Line 43  class Shape: Line 50  class Shape:
50          self.urx = max(xs)          self.urx = max(xs)
51          self.ury = max(ys)          self.ury = max(ys)
52    
53            self.bbox = (self.llx, self.lly, self.urx, self.ury)
54    
55            return self.bbox
56    
57      def Points(self):      def Points(self):
58          return self.points          return self.points
59    
# Line 66  class BaseLayer(TitledObject, Modifiable Line 77  class BaseLayer(TitledObject, Modifiable
77    
78      """Base class for the layers."""      """Base class for the layers."""
79    
80      def __init__(self, title, visible = 1):      def __init__(self, title, visible = True, projection = None):
81          """Initialize the layer.          """Initialize the layer.
82    
83          title -- the title          title -- the title
# Line 75  class BaseLayer(TitledObject, Modifiable Line 86  class BaseLayer(TitledObject, Modifiable
86          TitledObject.__init__(self, title)          TitledObject.__init__(self, title)
87          Modifiable.__init__(self)          Modifiable.__init__(self)
88          self.visible = visible          self.visible = visible
89            self.projection = projection
90    
91      def Visible(self):      def Visible(self):
92          """Return true if layer is visible"""          """Return true if layer is visible"""
# Line 85  class BaseLayer(TitledObject, Modifiable Line 97  class BaseLayer(TitledObject, Modifiable
97          self.visible = visible          self.visible = visible
98          self.issue(LAYER_VISIBILITY_CHANGED, self)          self.issue(LAYER_VISIBILITY_CHANGED, self)
99    
100        def HasClassification(self):
101            """Determine if this layer support classifications."""
102            return False
103    
104        def GetProjection(self):
105            """Return the layer's projection."""
106            return self.projection
107    
108        def SetProjection(self, projection):
109            """Set the layer's projection"""
110            self.projection = projection
111            self.changed(LAYER_PROJECTION_CHANGED, self)
112    
113  class Layer(BaseLayer):  class Layer(BaseLayer):
114    
# Line 106  class Layer(BaseLayer): Line 130  class Layer(BaseLayer):
130                   fill = Color.Transparent,                   fill = Color.Transparent,
131                   stroke = Color.Black,                   stroke = Color.Black,
132                   lineWidth = 1,                   lineWidth = 1,
133                   visible = 1):                   visible = True):
134          """Initialize the layer.          """Initialize the layer.
135    
136          title -- the title          title -- the title
# Line 122  class Layer(BaseLayer): Line 146  class Layer(BaseLayer):
146    
147          colors are expected to be instances of Color class          colors are expected to be instances of Color class
148          """          """
149          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title,
150                                     visible = visible,
151          self.projection = projection                                   projection = projection)
152    
153          #          #
154          # this is really important so that when the classification class          # this is really important so that when the classification class
# Line 149  class Layer(BaseLayer): Line 173  class Layer(BaseLayer):
173          self.store = store          self.store = store
174          self.shapefile = self.store.Shapefile()          self.shapefile = self.store.Shapefile()
175          self.shapetable = self.store.Table()          self.shapetable = self.store.Table()
176          self.filename = self.store.filename          if hasattr(self.store, "FileName"):
177                self.filename = self.store.FileName()
178          self.table = self.shapetable          self.table = self.shapetable
179    
180          numshapes, shapetype, mins, maxs = self.shapefile.info()          numshapes, shapetype, mins, maxs = self.shapefile.info()
# Line 174  class Layer(BaseLayer): Line 199  class Layer(BaseLayer):
199    
200          self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,          self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
201                                           maxdepth)                                           maxdepth)
202            # Set the classification to None if there is a classification
203            # and the new shapestore doesn't have a table with a suitable
204            # column, i.e one with the same name and type as before
205            # FIXME: Maybe we should keep it the same if the type is
206            # compatible enough such as FIELDTYPE_DOUBLE and FIELDTYPE_INT
207          if self.__classification is not None:          if self.__classification is not None:
208              fieldname = self.__classification.GetField()              fieldname = self.__classification.GetField()
209              if not self.store.Table().field_info_by_name(fieldname):              fieldtype = self.__classification.GetFieldType()
210                table = self.store.Table()
211                if (fieldname is not None
212                    and (not table.HasColumn(fieldname)
213                         or table.Column(fieldname).type != fieldtype)):
214                  self.SetClassification(None)                  self.SetClassification(None)
215          self.changed(LAYER_CHANGED, self)          self.changed(LAYER_SHAPESTORE_REPLACED, self)
216    
217      def ShapeStore(self):      def ShapeStore(self):
218          return self.store          return self.store
# Line 186  class Layer(BaseLayer): Line 220  class Layer(BaseLayer):
220      def Destroy(self):      def Destroy(self):
221          BaseLayer.Destroy(self)          BaseLayer.Destroy(self)
222          self.SetClassification(None)          self.SetClassification(None)
223            self.store = self.shapetree = None
224            self.table = self.shapefile = self.shapetable = None
225    
226      def BoundingBox(self):      def BoundingBox(self):
227          """Return the layer's bounding box in the intrinsic coordinate system.          """Return the layer's bounding box in the intrinsic coordinate system.
# Line 209  class Layer(BaseLayer): Line 245  class Layer(BaseLayer):
245          else:          else:
246              return None              return None
247    
248      def GetFieldType(self, fieldName):      def ShapesBoundingBox(self, shapes):
249          info = self.table.field_info_by_name(fieldName)          """Return a bounding box in lat/long coordinates for the given
250          if info is not None:          list of shape ids.
251              return info[0]  
252            If shapes is None or empty, return None.
253            """
254    
255            if shapes is None or len(shapes) == 0: return None
256    
257            llx = []
258            lly = []
259            urx = []
260            ury = []
261    
262            if self.projection is not None:
263                inverse = lambda x, y: self.projection.Inverse(x, y)
264          else:          else:
265              return None              inverse = lambda x, y: (x, y)
266    
267            for id in shapes:
268                left, bottom, right, top = self.Shape(id).compute_bbox()
269    
270                left, bottom = inverse(left, bottom)
271                right, top   = inverse(right, top)
272    
273                llx.append(left)
274                lly.append(bottom)
275                urx.append(right)
276                ury.append(top)
277    
278            return (min(llx), min(lly), max(urx), max(ury))
279    
280        def GetFieldType(self, fieldName):
281            if self.table.HasColumn(fieldName):
282                return self.table.Column(fieldName).type
283            return None
284    
285      def NumShapes(self):      def NumShapes(self):
286          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
# Line 244  class Layer(BaseLayer): Line 310  class Layer(BaseLayer):
310      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
311          """Return the ids of the shapes that overlap the box.          """Return the ids of the shapes that overlap the box.
312    
313          Box is a tuple (left, bottom, right, top) in the coordinate          Box is a tuple (left, bottom, right, top) in unprojected coordinates.
         system used by the layer's shapefile.  
314          """          """
315          left, bottom, right, top = box          left, bottom, right, top = box
         return self.shapetree.find_shapes((left, bottom), (right, top))  
316    
317      def GetProjection(self):          if self.projection is not None:
318          return self.projection              left,  bottom = self.projection.Forward(left, bottom)
319                right, top    = self.projection.Forward(right, top)
320    
321      def SetProjection(self, projection):          return self.shapetree.find_shapes((left, bottom), (right, top))
322          """Set the layer's projection"""  
323          self.projection = projection      def HasClassification(self):
324          self.changed(LAYER_PROJECTION_CHANGED, self)          return True
325    
326      def GetClassification(self):      def GetClassification(self):
327          return self.__classification          return self.__classification
# Line 295  class Layer(BaseLayer): Line 360  class Layer(BaseLayer):
360      def TreeInfo(self):      def TreeInfo(self):
361          items = []          items = []
362    
363            if hasattr(self, 'filename'):
364                items.append(_("Filename: %s") % self.filename)
365    
366          if self.Visible():          if self.Visible():
367              items.append(_("Shown"))              items.append(_("Shown"))
368          else:          else:
# Line 308  class Layer(BaseLayer): Line 376  class Layer(BaseLayer):
376              items.append(_("Extent (lat-lon):"))              items.append(_("Extent (lat-lon):"))
377          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
378    
379            if self.projection and len(self.projection.params) > 0:
380                items.append((_("Projection"),
381                            [str(param) for param in self.projection.params]))
382    
383          items.append(self.__classification)          items.append(self.__classification)
384    
385          return (_("Layer '%s'") % self.Title(), items)          return (_("Layer '%s'") % self.Title(), items)
386    
387    
388    class RasterLayer(BaseLayer):
389    
390        def __init__(self, title, filename, projection = None, visible = True):
391            """Initialize the Raster Layer.
392    
393            title -- title for the layer.
394    
395            filename -- file name of the source image.
396    
397            projection -- Projection object describing the projection which
398                          the source image is in.
399    
400            visible -- True is the layer should initially be visible.
401    
402            Throws IOError if the filename is invalid or points to a file that
403            is not in a format GDAL can use.
404            """
405    
406            BaseLayer.__init__(self, title, visible = visible)
407    
408            self.projection = projection
409            self.filename = filename
410    
411            self.bbox = -1
412    
413            #
414            # temporarily open the file so that GDAL can test if it's valid.
415            #
416            dataset = gdal.Open(self.filename, GA_ReadOnly)
417    
418            if dataset is None:
419                raise IOError()
420    
421            self.UnsetModified()
422    
423        def BoundingBox(self):
424            """Return the layer's bounding box in the intrinsic coordinate system.
425    
426            If the layer has no shapes, return None.
427            """
428            if self.bbox == -1:
429                dataset = gdal.Open(self.filename, GA_ReadOnly)
430                if dataset is None:
431                    self.bbox = None
432                else:
433                    geotransform = dataset.GetGeoTransform()
434                    if geotransform is None:
435                        return None
436    
437                    x = 0
438                    y = dataset.RasterYSize
439                    left = geotransform[0] +        \
440                           geotransform[1] * x +    \
441                           geotransform[2] * y
442    
443                    bottom = geotransform[3] +      \
444                             geotransform[4] * x +  \
445                             geotransform[5] * y
446    
447                    x = dataset.RasterXSize
448                    y = 0
449                    right = geotransform[0] +       \
450                            geotransform[1] * x +   \
451                            geotransform[2] * y
452    
453                    top = geotransform[3] +         \
454                          geotransform[4] * x +     \
455                          geotransform[5] * y
456    
457                    self.bbox = (left, bottom, right, top)
458    
459            return self.bbox
460    
461        def LatLongBoundingBox(self):
462            bbox = self.BoundingBox()
463            if bbox is None:
464                return None
465    
466            llx, lly, urx, ury = bbox
467            if self.projection is not None:
468                llx, lly = self.projection.Inverse(llx, lly)
469                urx, ury = self.projection.Inverse(urx, ury)
470    
471            return llx, lly, urx, ury
472    
473        def GetImageFilename(self):
474            return self.filename
475    
476        def TreeInfo(self):
477            items = []
478    
479            if self.Visible():
480                items.append(_("Shown"))
481            else:
482                items.append(_("Hidden"))
483            items.append(_("Shapes: %d") % self.NumShapes())
484    
485            bbox = self.LatLongBoundingBox()
486            if bbox is not None:
487                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
488            else:
489                items.append(_("Extent (lat-lon):"))
490    
491            if self.projection and len(self.projection.params) > 0:
492                items.append((_("Projection"),
493                            [str(param) for param in self.projection.params]))
494    
495            return (_("Layer '%s'") % self.Title(), items)
496    

Legend:
Removed from v.725  
changed lines
  Added in v.1142

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26