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

Legend:
Removed from v.723  
changed lines
  Added in v.1158

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26