/[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 143 by bh, Tue May 7 14:17:20 2002 UTC revision 771 by jonathan, Tue Apr 29 14:34:02 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.
8    
9  __version__ = "$Revision$"  __version__ = "$Revision$"
10    
11    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 63  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 81  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 97  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              #print "building tree for", self.filename, "..."          else:
164              self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2, 0)              self.bbox = None
165              #print "done"  
166            # estimate a good depth for the quad tree. Each depth
167            # multiplies the number of nodes by four, therefore we
168            # basically take the base 4 logarithm of the number of
169            # shapes.
170            if self.numshapes < 4:
171                maxdepth = 1
172            else:
173                maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
174    
175            self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
176                                             maxdepth)
177            if self.__classification is not None:
178                fieldname = self.__classification.GetField()
179                if not self.store.Table().field_info_by_name(fieldname):
180                    self.SetClassification(None)
181            self.changed(LAYER_CHANGED, self)
182    
183        def ShapeStore(self):
184            return self.store
185    
186        def Destroy(self):
187            BaseLayer.Destroy(self)
188            self.SetClassification(None)
189    
190      def BoundingBox(self):      def BoundingBox(self):
191          """Return the bounding box of the layer's shapes in their default          """Return the layer's bounding box in the intrinsic coordinate system.
192          coordinate system"""  
193          self.open_shapefile()          If the layer has no shapes, return None.
194            """
195          return self.bbox          return self.bbox
196    
197      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
198          """Return the layer's bounding box in lat/long coordinates"""          """Return the layer's bounding box in lat/long coordinates.
199          llx, lly, urx, ury = self.BoundingBox()  
200          if self.projection is not None:          Return None, if the layer doesn't contain any shapes.
201              llx, lly = self.projection.Inverse(llx, lly)          """
202              urx, ury = self.projection.Inverse(urx, ury)          bbox = self.BoundingBox()
203          return llx, lly, urx, ury          if bbox is not None:
204                llx, lly, urx, ury = bbox
205                if self.projection is not None:
206                    llx, lly = self.projection.Inverse(llx, lly)
207                    urx, ury = self.projection.Inverse(urx, ury)
208                return llx, lly, urx, ury
209            else:
210                return None
211    
212        def GetFieldType(self, fieldName):
213            info = self.table.field_info_by_name(fieldName)
214            if info is not None:
215                return info[0]
216            else:
217                return None
218    
219      def NumShapes(self):      def NumShapes(self):
220          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
         self.open_shapefile()  
221          return self.numshapes          return self.numshapes
222    
223      def ShapeType(self):      def ShapeType(self):
224          """Return the type of the shapes in the layer.          """Return the type of the shapes in the layer.
225          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
226          """          """
         self.open_shapefile()  
227          return self.shapetype          return self.shapetype
228    
229      def Shape(self, index):      def Shape(self, index):
230          """Return the shape with index index"""          """Return the shape with index index"""
         self.open_shapefile()  
231          shape = self.shapefile.read_object(index)          shape = self.shapefile.read_object(index)
232    
233          if self.shapetype == SHAPETYPE_POINT:          if self.shapetype == SHAPETYPE_POINT:
234              points = shape.vertices()              points = shape.vertices()
235          else:          else:
# Line 180  class Layer(BaseLayer): Line 238  class Layer(BaseLayer):
238              points = []              points = []
239              for x, y in poly:              for x, y in poly:
240                  points.append((x, y))                  points.append((x, y))
241    
242          return Shape(points)          return Shape(points)
243    
244      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
# Line 189  class Layer(BaseLayer): Line 248  class Layer(BaseLayer):
248          system used by the layer's shapefile.          system used by the layer's shapefile.
249          """          """
250          left, bottom, right, top = box          left, bottom, right, top = box
251          import time          return self.shapetree.find_shapes((left, bottom), (right, top))
252          start = time.time()  
253          ids = self.shapetree.find_shapes((left, bottom), (right, top))      def GetProjection(self):
254          print "ShapesInRegion", time.time() - start          return self.projection
         return ids  
255    
256      def SetProjection(self, projection):      def SetProjection(self, projection):
257          """Set the layer's projection"""          """Set the layer's projection"""
258          self.projection = projection          self.projection = projection
259          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
260    
261      def SetFill(self, fill):      def GetClassification(self):
262          """Set the layer's fill color. None means the shapes are not filled"""          return self.__classification
263          self.fill = fill  
264          self.changed(LAYER_LEGEND_CHANGED, self)      def SetClassification(self, clazz):
265            """Set the classification to 'clazz'
266      def SetStroke(self, stroke):  
267          """Set the layer's stroke color. None means the shapes are not          If 'clazz' is None a default classification is created
268          stroked."""          """
269          self.stroke = stroke  
270          self.changed(LAYER_LEGEND_CHANGED, self)          # prevent infinite recursion when calling SetLayer()
271            if self.__setClassLock: return
272      def SetStrokeWidth(self, width):  
273          """Set the layer's stroke width."""          self.__setClassLock = True
274          self.stroke_width = width  
275          self.changed(LAYER_LEGEND_CHANGED, self)          if clazz is None:
276                if self.__classification is not None:
277                    self.__classification.SetLayer(None)
278                self.__classification = classification.Classification()
279            else:
280                self.__classification = clazz
281                try:
282                    self.__classification.SetLayer(self)
283                except ValueError:
284                    self.__setClassLock = False
285                    raise ValueError
286    
287            self.changed(LAYER_CHANGED, self)
288    
289            self.__setClassLock = False
290    
291        def ClassChanged(self):
292            """Called from the classification object when it has changed."""
293            self.changed(LAYER_CHANGED, self)
294    
295        def TreeInfo(self):
296            items = []
297    
298            if self.Visible():
299                items.append(_("Shown"))
300            else:
301                items.append(_("Hidden"))
302            items.append(_("Shapes: %d") % self.NumShapes())
303    
304            bbox = self.LatLongBoundingBox()
305            if bbox is not None:
306                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
307            else:
308                items.append(_("Extent (lat-lon):"))
309            items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
310    
311            if self.projection and len(self.projection.params) > 0:
312                items.append((_("Projection"),
313                            [str(param) for param in self.projection.params]))
314    
315            items.append(self.__classification)
316    
317            return (_("Layer '%s'") % self.Title(), items)
318    
319    

Legend:
Removed from v.143  
changed lines
  Added in v.771

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26