/[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 1978 by bh, Tue Nov 25 14:30:34 2003 UTC revision 2644 by bh, Tue Jul 5 16:30:51 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004, 2005 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.
# Line 24  from data import SHAPETYPE_POLYGON, SHAP Line 25  from data import SHAPETYPE_POLYGON, SHAP
25    
26  import resource  import resource
27    
28    from color import Color
29    
30  shapetype_names = {SHAPETYPE_POINT: "Point",  shapetype_names = {SHAPETYPE_POINT: "Point",
31                     SHAPETYPE_ARC: "Arc",                     SHAPETYPE_ARC: "Arc",
# Line 54  class BaseLayer(TitledObject, Modifiable Line 56  class BaseLayer(TitledObject, Modifiable
56          self.issue(LAYER_VISIBILITY_CHANGED, self)          self.issue(LAYER_VISIBILITY_CHANGED, self)
57    
58      def HasClassification(self):      def HasClassification(self):
59          """Determine if this layer support classifications."""          """Determine if this layer supports classifications."""
60          return False          return False
61    
62      def HasShapes(self):      def HasShapes(self):
# Line 66  class BaseLayer(TitledObject, Modifiable Line 68  class BaseLayer(TitledObject, Modifiable
68          return self.projection          return self.projection
69    
70      def SetProjection(self, projection):      def SetProjection(self, projection):
71          """Set the layer's projection"""          """Set the layer's projection."""
72          self.projection = projection          self.projection = projection
73          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
74    
75        def Type(self):
76            return "Unknown"
77    
78  class Layer(BaseLayer):  class Layer(BaseLayer):
79    
80      """Represent the information of one geodata file (currently a shapefile)      """Represent the information of one geodata file (currently a shapefile)
# Line 166  class Layer(BaseLayer): Line 171  class Layer(BaseLayer):
171          Return None, if the layer doesn't contain any shapes.          Return None, if the layer doesn't contain any shapes.
172          """          """
173          bbox = self.BoundingBox()          bbox = self.BoundingBox()
174          if bbox is not None:          if bbox is not None and self.projection is not None:
175              llx, lly, urx, ury = bbox              bbox = self.projection.InverseBBox(bbox)
176              if self.projection is not None:          return bbox
177                  llx, lly = self.projection.Inverse(llx, lly)  
178                  urx, ury = self.projection.Inverse(urx, ury)      def Type(self):
179              return llx, lly, urx, ury          return self.ShapeType();
         else:  
             return None  
180    
181      def ShapesBoundingBox(self, shapes):      def ShapesBoundingBox(self, shapes):
182          """Return a bounding box in lat/long coordinates for the given          """Return a bounding box in lat/long coordinates for the given
# Line 184  class Layer(BaseLayer): Line 187  class Layer(BaseLayer):
187    
188          if shapes is None or len(shapes) == 0: return None          if shapes is None or len(shapes) == 0: return None
189    
190          llx = []          xs = []
191          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)  
192    
193          for id in shapes:          for id in shapes:
194              left, bottom, right, top = self.Shape(id).compute_bbox()              bbox = self.Shape(id).compute_bbox()
195                if self.projection is not None:
196              left, bottom = inverse(left, bottom)                  bbox = self.projection.InverseBBox(bbox)
197              right, top   = inverse(right, top)              left, bottom, right, top = bbox
198                xs.append(left); xs.append(right)
199                ys.append(bottom); ys.append(top)
200    
201              llx.append(left)          return (min(xs), min(ys), max(xs), max(ys))
             lly.append(bottom)  
             urx.append(right)  
             ury.append(top)  
202    
         return (min(llx), min(lly), max(urx), max(ury))  
203    
204      def GetFieldType(self, fieldName):      def GetFieldType(self, fieldName):
205          if self.store:          if self.store:
# Line 240  class Layer(BaseLayer): Line 234  class Layer(BaseLayer):
234          form (minx, miny, maxx, maxy) in unprojected coordinates.          form (minx, miny, maxx, maxy) in unprojected coordinates.
235          """          """
236          if self.projection is not None:          if self.projection is not None:
237              left, bottom, right, top = bbox              # Ensure that region lies within the layer's bounding box
238              xs = []; ys = []              # Otherwise projection of the region would lead to incorrect
239              for x, y in [(left, bottom), (left, top), (right, top),              # values.
240                           (right, bottom)]:              clipbbox = self.__mangle_bounding_box(bbox)
241                  x, y = self.projection.Forward(x, y)              bbox = self.projection.ForwardBBox(clipbbox)
                 xs.append(x)  
                 ys.append(y)  
             bbox = (min(xs), min(ys), max(xs), max(ys))  
   
242          return self.store.ShapesInRegion(bbox)          return self.store.ShapesInRegion(bbox)
243    
244      def GetClassificationColumn(self):      def GetClassificationColumn(self):
# Line 311  class Layer(BaseLayer): Line 301  class Layer(BaseLayer):
301    
302          bbox = self.LatLongBoundingBox()          bbox = self.LatLongBoundingBox()
303          if bbox is not None:          if bbox is not None:
304              items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)              items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % tuple(bbox))
305          else:          else:
306              items.append(_("Extent (lat-lon):"))              items.append(_("Extent (lat-lon):"))
307          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
# Line 324  class Layer(BaseLayer): Line 314  class Layer(BaseLayer):
314    
315          return (_("Layer '%s'") % self.Title(), items)          return (_("Layer '%s'") % self.Title(), items)
316    
317        def __mangle_bounding_box(self, bbox):
318            # FIXME: This method doesn't make much sense.
319            # See RT #2845 which effectively says:
320            #
321            # If this method, which was originally called ClipBoundingBox,
322            # is supposed to do clipping it shouldn't return the parameter
323            # unchanged when it lies completely outside of the bounding box.
324            # It would be better to return None and return an empty list in
325            # ShapesInRegion (the only caller) in that case.
326            #
327            # This method was introduced to fix a bug that IIRC had
328            # something todo with projections and bounding boxes containing
329            # NaN or INF when the parameter to ShapesInRegion covered the
330            # entire earth or something similarly large).
331            bminx, bminy, bmaxx, bmaxy = bbox
332            lminx, lminy, lmaxx, lmaxy = self.LatLongBoundingBox()
333            if bminx > lmaxx or bmaxx < lminx:
334                left, right = bminx, bmaxx
335            else:
336                left = max(lminx, bminx)
337                right = min(lmaxx, bmaxx)
338            if bminy > lmaxy or bmaxy < lminy:
339                bottom, top = bminy, bmaxy
340            else:
341                bottom = max(lminy, bminy)
342                top = min(lmaxy, bmaxy)
343    
344            return (left, bottom, right, top)
345    
346    
347  if resource.has_gdal_support():  if resource.has_gdal_support():
348      import gdal      import gdal
# Line 331  if resource.has_gdal_support(): Line 350  if resource.has_gdal_support():
350    
351  class RasterLayer(BaseLayer):  class RasterLayer(BaseLayer):
352    
353      def __init__(self, title, filename, projection = None, visible = True):      MASK_NONE  = 0
354        MASK_BIT   = 1
355        MASK_ALPHA = 2
356    
357        def __init__(self, title, filename, projection = None,
358                     visible = True, opacity = 1, masktype = MASK_BIT):
359          """Initialize the Raster Layer.          """Initialize the Raster Layer.
360    
361          title -- title for the layer.          title -- title for the layer.
# Line 354  class RasterLayer(BaseLayer): Line 378  class RasterLayer(BaseLayer):
378    
379          self.bbox = -1          self.bbox = -1
380    
381            self.mask_type = masktype
382            self.opacity = opacity
383    
384            self.image_info = None
385    
386          if resource.has_gdal_support():          if resource.has_gdal_support():
387              #              #
388              # temporarily open the file so that GDAL can test if it's valid.              # temporarily open the file so that GDAL can test if it's valid.
# Line 363  class RasterLayer(BaseLayer): Line 392  class RasterLayer(BaseLayer):
392              if dataset is None:              if dataset is None:
393                  raise IOError()                  raise IOError()
394    
395                #
396                # while we have the file, extract some basic information
397                # that we can display later
398                #
399                self.image_info = {}
400    
401                self.image_info["nBands"] = dataset.RasterCount
402                self.image_info["Size"] = (dataset.RasterXSize, dataset.RasterYSize)
403                self.image_info["Driver"] = dataset.GetDriver().ShortName
404    
405                # store some information about the individual bands
406                # [min_value, max_value]
407                a = self.image_info["BandData"] = []
408    
409                for i in range(1, dataset.RasterCount+1):
410                    band = dataset.GetRasterBand(i)
411                    a.append(band.ComputeRasterMinMax())
412    
413          self.UnsetModified()          self.UnsetModified()
414    
415      def BoundingBox(self):      def BoundingBox(self):
# Line 412  class RasterLayer(BaseLayer): Line 459  class RasterLayer(BaseLayer):
459          if bbox is None:          if bbox is None:
460              return None              return None
461    
         llx, lly, urx, ury = bbox  
462          if self.projection is not None:          if self.projection is not None:
463              llx, lly = self.projection.Inverse(llx, lly)              bbox = self.projection.InverseBBox(bbox)
464              urx, ury = self.projection.Inverse(urx, ury)  
465            return bbox
466    
467          return llx, lly, urx, ury      def Type(self):
468            return "Image"
469    
470      def GetImageFilename(self):      def GetImageFilename(self):
471          return self.filename          return self.filename
472    
473        def MaskType(self):
474            """Return True if the mask should be used when rendering the layer."""
475            return self.mask_type
476    
477        def SetMaskType(self, type):
478            """Set the type of mask to use.
479    
480            type can be one of MASK_NONE, MASK_BIT, MASK_ALPHA
481    
482            If the state changes, a LAYER_CHANGED message is sent.
483            """
484            if type not in (self.MASK_NONE, self.MASK_BIT, self.MASK_ALPHA):
485                raise ValueError("type is invalid")
486    
487            if type != self.mask_type:
488                self.mask_type = type
489                self.changed(LAYER_CHANGED, self)
490    
491        def Opacity(self):
492            """Return the level of opacity used in alpha blending.
493            """
494            return self.opacity
495    
496        def SetOpacity(self, op):
497            """Set the level of alpha opacity.
498    
499            0 <= op <= 1.
500    
501            The layer is fully opaque when op = 1.
502            """
503            if not (0 <= op <= 1):
504                raise ValueError("op out of range")
505    
506            if op != self.opacity:
507                self.opacity = op
508                self.changed(LAYER_CHANGED, self)
509    
510        def ImageInfo(self):
511            return self.image_info
512    
513      def TreeInfo(self):      def TreeInfo(self):
514          items = []          items = []
515    

Legend:
Removed from v.1978  
changed lines
  Added in v.2644

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26