/[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 171 by bh, Tue May 14 14:16:24 2002 UTC revision 791 by jan, Wed Apr 30 12:26:33 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4    # Jonathan Coles <[email protected]>
5  #  #
6  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
7  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 9  __version__ = "$Revision$" Line 10  __version__ = "$Revision$"
10    
11  from math import log, ceil  from math import log, ceil
12    
13    from Thuban import _
14    
15  import shapelib, shptree  import shapelib, shptree
16    
17  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
18       LAYER_VISIBILITY_CHANGED       LAYER_CHANGED
19    
20  from color import Color  from color import Color
 # Some predefined colors for internal use  
 _black = Color(0, 0, 0)  
   
21    
22  from table import Table  import classification
23    
24  from base import TitledObject, Modifiable  from base import TitledObject, Modifiable
25    
26    
27  class Shape:  class Shape:
28    
29      """Represent one shape"""      """Represent one shape"""
# Line 65  class BaseLayer(TitledObject, Modifiable Line 66  class BaseLayer(TitledObject, Modifiable
66    
67      """Base class for the layers."""      """Base class for the layers."""
68    
69      def __init__(self, title, visible = 1):      def __init__(self, title, visible = True):
70          """Initialize the layer.          """Initialize the layer.
71    
72          title -- the title          title -- the title
# Line 83  class BaseLayer(TitledObject, Modifiable Line 84  class BaseLayer(TitledObject, Modifiable
84          """Set the layer's visibility."""          """Set the layer's visibility."""
85          self.visible = visible          self.visible = visible
86          self.issue(LAYER_VISIBILITY_CHANGED, self)          self.issue(LAYER_VISIBILITY_CHANGED, self)
87            
88            
89  class Layer(BaseLayer):  class Layer(BaseLayer):
90    
91      """Represent the information of one geodata file (currently a shapefile)      """Represent the information of one geodata file (currently a shapefile)
# Line 99  class Layer(BaseLayer): Line 100  class Layer(BaseLayer):
100    
101          TITLE_CHANGED -- The title has changed.          TITLE_CHANGED -- The title has changed.
102          LAYER_PROJECTION_CHANGED -- the projection has changed.          LAYER_PROJECTION_CHANGED -- the projection has changed.
         LAYER_LEGEND_CHANGED -- the fill or stroke attributes have changed  
   
103      """      """
104    
105      def __init__(self, title, filename, projection = None,      def __init__(self, title, data, projection = None,
106                   fill = None, stroke = _black, stroke_width = 1, visible = 1):                   fill = Color.Transparent,
107                     stroke = Color.Black,
108                     lineWidth = 1,
109                     visible = True):
110          """Initialize the layer.          """Initialize the layer.
111    
112          title -- the title          title -- the title
113          filename -- the name of the shapefile          data -- datastore object for the shape data shown by the layer
114          projection -- the projection object. Its Inverse method is          projection -- the projection object. Its Inverse method is
115                 assumed to map the layer's coordinates to lat/long                 assumed to map the layer's coordinates to lat/long
116                 coordinates                 coordinates
117          fill -- the fill color or None if the shapes are not filled          fill -- the fill color or Color.Transparent if the shapes are
118          stroke -- the stroke color or None if the shapes are not stroked                  not filled
119            stroke -- the stroke color or Color.Transparent if the shapes
120                    are not stroked
121          visible -- boolean. If true the layer is visible.          visible -- boolean. If true the layer is visible.
122    
123          colors are expected to be instances of Color class          colors are expected to be instances of Color class
124          """          """
125          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title, visible = visible)
126          self.filename = filename  
127          self.projection = projection          self.projection = projection
128          self.fill = fill  
129          self.stroke = stroke          #
130          self.stroke_width = stroke_width          # this is really important so that when the classification class
131          self.shapefile = None          # tries to set its parent layer the variable will exist
132          self.shapetree = None          #
133          self.open_shapefile()          self.__classification = None
134          # shapetable is the table associated with the shapefile, while          self.__setClassLock = False
135          # table is the default table used to look up attributes for  
136          # display          self.SetShapeStore(data)
137          self.shapetable = Table(filename)  
138            self.SetClassification(None)
139    
140            self.__classification.SetDefaultLineColor(stroke)
141            self.__classification.SetDefaultLineWidth(lineWidth)
142            self.__classification.SetDefaultFill(fill)
143            self.__classification.SetLayer(self)
144    
145            self.UnsetModified()
146    
147    
148        def SetShapeStore(self, store):
149            self.store = store
150            self.shapefile = self.store.Shapefile()
151            self.shapetable = self.store.Table()
152            self.filename = self.store.filename
153          self.table = self.shapetable          self.table = self.shapetable
154    
155      def open_shapefile(self):          numshapes, shapetype, mins, maxs = self.shapefile.info()
156          if self.shapefile is None:          self.numshapes = numshapes
157              self.shapefile = shapelib.ShapeFile(self.filename)          self.shapetype = shapelib_shapetypes[shapetype]
158              numshapes, shapetype, mins, maxs = self.shapefile.info()  
159              self.numshapes = numshapes          # if there are shapes, set the bbox accordingly. Otherwise
160              self.shapetype = shapelib_shapetypes[shapetype]          # set it to None.
161            if self.numshapes:
162              self.bbox = mins[:2] + maxs[:2]              self.bbox = mins[:2] + maxs[:2]
163            else:
164                self.bbox = None
165    
166              # estimate a good depth for the quad tree. Each depth          # estimate a good depth for the quad tree. Each depth
167              # multiplies the number of nodes by four, therefore we          # multiplies the number of nodes by four, therefore we
168              # basically take the base 4 logarithm of the number of          # basically take the base 4 logarithm of the number of
169              # shapes.          # shapes.
170              if self.numshapes < 4:          if self.numshapes < 4:
171                  maxdepth = 1              maxdepth = 1
172              else:          else:
173                  maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))              maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
174    
175              self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,          self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
176                                               maxdepth)                                           maxdepth)
177            if self.__classification is not None:
178                fieldname = self.__classification.GetField()
179                if fieldname is not None and \
180                   not self.store.Table().field_info_by_name(fieldname):
181                    self.SetClassification(None)
182            self.changed(LAYER_CHANGED, self)
183    
184        def ShapeStore(self):
185            return self.store
186    
187        def Destroy(self):
188            BaseLayer.Destroy(self)
189            self.SetClassification(None)
190    
191      def BoundingBox(self):      def BoundingBox(self):
192          """Return the bounding box of the layer's shapes in their default          """Return the layer's bounding box in the intrinsic coordinate system.
193          coordinate system"""  
194          self.open_shapefile()          If the layer has no shapes, return None.
195            """
196          return self.bbox          return self.bbox
197    
198      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
199          """Return the layer's bounding box in lat/long coordinates"""          """Return the layer's bounding box in lat/long coordinates.
200          llx, lly, urx, ury = self.BoundingBox()  
201          if self.projection is not None:          Return None, if the layer doesn't contain any shapes.
202              llx, lly = self.projection.Inverse(llx, lly)          """
203              urx, ury = self.projection.Inverse(urx, ury)          bbox = self.BoundingBox()
204          return llx, lly, urx, ury          if bbox is not None:
205                llx, lly, urx, ury = bbox
206                if self.projection is not None:
207                    llx, lly = self.projection.Inverse(llx, lly)
208                    urx, ury = self.projection.Inverse(urx, ury)
209                return llx, lly, urx, ury
210            else:
211                return None
212    
213        def GetFieldType(self, fieldName):
214            info = self.table.field_info_by_name(fieldName)
215            if info is not None:
216                return info[0]
217            else:
218                return None
219    
220      def NumShapes(self):      def NumShapes(self):
221          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
         self.open_shapefile()  
222          return self.numshapes          return self.numshapes
223    
224      def ShapeType(self):      def ShapeType(self):
225          """Return the type of the shapes in the layer.          """Return the type of the shapes in the layer.
226          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
227          """          """
         self.open_shapefile()  
228          return self.shapetype          return self.shapetype
229    
230      def Shape(self, index):      def Shape(self, index):
231          """Return the shape with index index"""          """Return the shape with index index"""
         self.open_shapefile()  
232          shape = self.shapefile.read_object(index)          shape = self.shapefile.read_object(index)
233    
234          if self.shapetype == SHAPETYPE_POINT:          if self.shapetype == SHAPETYPE_POINT:
235              points = shape.vertices()              points = shape.vertices()
236          else:          else:
# Line 191  class Layer(BaseLayer): Line 239  class Layer(BaseLayer):
239              points = []              points = []
240              for x, y in poly:              for x, y in poly:
241                  points.append((x, y))                  points.append((x, y))
242    
243          return Shape(points)          return Shape(points)
244    
245      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
# Line 202  class Layer(BaseLayer): Line 251  class Layer(BaseLayer):
251          left, bottom, right, top = box          left, bottom, right, top = box
252          return self.shapetree.find_shapes((left, bottom), (right, top))          return self.shapetree.find_shapes((left, bottom), (right, top))
253    
254        def GetProjection(self):
255            return self.projection
256    
257      def SetProjection(self, projection):      def SetProjection(self, projection):
258          """Set the layer's projection"""          """Set the layer's projection"""
259          self.projection = projection          self.projection = projection
260          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
261    
262      def SetFill(self, fill):      def GetClassification(self):
263          """Set the layer's fill color. None means the shapes are not filled"""          return self.__classification
264          self.fill = fill  
265          self.changed(LAYER_LEGEND_CHANGED, self)      def SetClassification(self, clazz):
266            """Set the classification to 'clazz'
267      def SetStroke(self, stroke):  
268          """Set the layer's stroke color. None means the shapes are not          If 'clazz' is None a default classification is created
269          stroked."""          """
270          self.stroke = stroke  
271          self.changed(LAYER_LEGEND_CHANGED, self)          # prevent infinite recursion when calling SetLayer()
272            if self.__setClassLock: return
273      def SetStrokeWidth(self, width):  
274          """Set the layer's stroke width."""          self.__setClassLock = True
275          self.stroke_width = width  
276          self.changed(LAYER_LEGEND_CHANGED, self)          if clazz is None:
277                if self.__classification is not None:
278                    self.__classification.SetLayer(None)
279                self.__classification = classification.Classification()
280            else:
281                self.__classification = clazz
282                try:
283                    self.__classification.SetLayer(self)
284                except ValueError:
285                    self.__setClassLock = False
286                    raise ValueError
287    
288            self.changed(LAYER_CHANGED, self)
289    
290            self.__setClassLock = False
291    
292        def ClassChanged(self):
293            """Called from the classification object when it has changed."""
294            self.changed(LAYER_CHANGED, self)
295    
296        def TreeInfo(self):
297            items = []
298    
299            if self.Visible():
300                items.append(_("Shown"))
301            else:
302                items.append(_("Hidden"))
303            items.append(_("Shapes: %d") % self.NumShapes())
304    
305            bbox = self.LatLongBoundingBox()
306            if bbox is not None:
307                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
308            else:
309                items.append(_("Extent (lat-lon):"))
310            items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
311    
312            if self.projection and len(self.projection.params) > 0:
313                items.append((_("Projection"),
314                            [str(param) for param in self.projection.params]))
315    
316            items.append(self.__classification)
317    
318            return (_("Layer '%s'") % self.Title(), items)
319    
320    

Legend:
Removed from v.171  
changed lines
  Added in v.791

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26