/[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 6 by bh, Tue Aug 28 15:41:52 2001 UTC revision 492 by jonathan, Mon Mar 10 10:44:57 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002 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  import shapelib  import os
12    from math import log, ceil
13    
14    from Thuban import _
15    
16    import shapelib, shptree
17    
18  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
19       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED
20    
21  from color import Color  from color import Color
 # Some predefined colors for internal use  
 _black = Color(0, 0, 0)  
22    
23    import classification
24    
25  from table import Table  from table import Table
26    
# Line 81  class BaseLayer(TitledObject, Modifiable Line 86  class BaseLayer(TitledObject, Modifiable
86          """Set the layer's visibility."""          """Set the layer's visibility."""
87          self.visible = visible          self.visible = visible
88          self.issue(LAYER_VISIBILITY_CHANGED, self)          self.issue(LAYER_VISIBILITY_CHANGED, self)
89            
90            
91  class Layer(BaseLayer):  class Layer(BaseLayer):
92    
93      """Represent the information of one geodata file (currently a shapefile)      """Represent the information of one geodata file (currently a shapefile)
# Line 102  class Layer(BaseLayer): Line 107  class Layer(BaseLayer):
107      """      """
108    
109      def __init__(self, title, filename, projection = None,      def __init__(self, title, filename, projection = None,
110                   fill = None, stroke = _black, visible = 1):                   fill = Color.None,
111                     stroke = Color.Black,
112                     lineWidth = 1,
113                     visible = 1):
114          """Initialize the layer.          """Initialize the layer.
115    
116          title -- the title          title -- the title
# Line 110  class Layer(BaseLayer): Line 118  class Layer(BaseLayer):
118          projection -- the projection object. Its Inverse method is          projection -- the projection object. Its Inverse method is
119                 assumed to map the layer's coordinates to lat/long                 assumed to map the layer's coordinates to lat/long
120                 coordinates                 coordinates
121          fill -- the fill color or None if the shapes are not filled          fill -- the fill color or Color.None if the shapes are not filled
122          stroke -- the stroke color or None if the shapes are not stroked          stroke -- the stroke color or Color.None if the shapes are not stroked
123          visible -- boolean. If true the layer is visible.          visible -- boolean. If true the layer is visible.
124    
125          colors are expected to be instances of Color class          colors are expected to be instances of Color class
126          """          """
127          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title, visible = visible)
128          self.filename = filename  
129            # Make the filename absolute. The filename will be
130            # interpreted relative to that anyway, but when saving a
131            # session we need to compare absolute paths and it's usually
132            # safer to always work with absolute paths.
133            self.filename = os.path.abspath(filename)
134    
135          self.projection = projection          self.projection = projection
         self.fill = fill  
         self.stroke = stroke  
136          self.shapefile = None          self.shapefile = None
137            self.shapetree = None
138            self.open_shapefile()
139          # shapetable is the table associated with the shapefile, while          # shapetable is the table associated with the shapefile, while
140          # table is the default table used to look up attributes for          # table is the default table used to look up attributes for
141          # display          # display
142          self.shapetable = Table(filename)          self.shapetable = Table(filename)
143          self.table = self.shapetable          self.table = self.shapetable
144    
145            #
146            # this is really important so that when the classification class
147            # tries to set its parent layer the variable will exist
148            #
149            self.__classification = None
150    
151    
152            self.SetClassification(None)
153    
154            self.__classification.SetDefaultLineColor(stroke)
155            self.__classification.SetDefaultLineWidth(lineWidth)
156            self.__classification.SetDefaultFill(fill)
157            self.__classification.SetLayer(self)
158    
159            self.UnsetModified()
160    
161      def open_shapefile(self):      def open_shapefile(self):
162          if self.shapefile is None:          if self.shapefile is None:
163              self.shapefile = shapelib.ShapeFile(self.filename)              self.shapefile = shapelib.ShapeFile(self.filename)
164              numshapes, shapetype, mins, maxs = self.shapefile.info()              numshapes, shapetype, mins, maxs = self.shapefile.info()
165              self.numshapes = numshapes              self.numshapes = numshapes
166              self.shapetype = shapelib_shapetypes[shapetype]              self.shapetype = shapelib_shapetypes[shapetype]
167              self.bbox = mins[:2] + maxs[:2]  
168                # if there are shapes, set the bbox accordinly. Otherwise
169                # set it to None.
170                if self.numshapes:
171                    self.bbox = mins[:2] + maxs[:2]
172                else:
173                    self.bbox = None
174    
175                # estimate a good depth for the quad tree. Each depth
176                # multiplies the number of nodes by four, therefore we
177                # basically take the base 4 logarithm of the number of
178                # shapes.
179                if self.numshapes < 4:
180                    maxdepth = 1
181                else:
182                    maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
183    
184                self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
185                                                 maxdepth)
186    
187        def Destroy(self):
188            BaseLayer.Destroy(self)
189            if self.shapefile is not None:
190                self.shapefile.close()
191                self.shapefile = None
192                self.shapetree = None
193            self.table.Destroy()
194    
195      def BoundingBox(self):      def BoundingBox(self):
196          """Return the bounding box of the layer's shapes in their default          """Return the layer's bounding box in the intrinsic coordinate system.
197          coordinate system"""  
198            If the layer has no shapes, return None.
199            """
200            # The bbox will be set by open_shapefile just as we need it
201            # here.
202          self.open_shapefile()          self.open_shapefile()
203          return self.bbox          return self.bbox
204    
205      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
206          """Return the layer's bounding box in lat/long coordinates"""          """Return the layer's bounding box in lat/long coordinates.
207          llx, lly, urx, ury = self.BoundingBox()  
208          if self.projection is not None:          Return None, if the layer doesn't contain any shapes.
209              llx, lly = self.projection.Inverse(llx, lly)          """
210              urx, ury = self.projection.Inverse(urx, ury)          bbox = self.BoundingBox()
211          return llx, lly, urx, ury          if bbox is not None:
212                llx, lly, urx, ury = bbox
213                if self.projection is not None:
214                    llx, lly = self.projection.Inverse(llx, lly)
215                    urx, ury = self.projection.Inverse(urx, ury)
216                return llx, lly, urx, ury
217            else:
218                return None
219    
220        def GetFieldType(self, fieldName):
221            self.open_shapefile()
222            info = self.table.field_info_by_name(fieldName)
223            if info is not None:
224                return info[0]
225            else:
226                return None
227    
228      def NumShapes(self):      def NumShapes(self):
229          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
# Line 166  class Layer(BaseLayer): Line 241  class Layer(BaseLayer):
241          """Return the shape with index index"""          """Return the shape with index index"""
242          self.open_shapefile()          self.open_shapefile()
243          shape = self.shapefile.read_object(index)          shape = self.shapefile.read_object(index)
244    
245          if self.shapetype == SHAPETYPE_POINT:          if self.shapetype == SHAPETYPE_POINT:
246              points = shape.vertices()              points = shape.vertices()
247          else:          else:
# Line 173  class Layer(BaseLayer): Line 249  class Layer(BaseLayer):
249              poly = shape.vertices()[0]              poly = shape.vertices()[0]
250              points = []              points = []
251              for x, y in poly:              for x, y in poly:
252                  points.append(x, y)                  points.append((x, y))
253    
254          return Shape(points)          return Shape(points)
255    
256        def ShapesInRegion(self, box):
257            """Return the ids of the shapes that overlap the box.
258    
259            Box is a tuple (left, bottom, right, top) in the coordinate
260            system used by the layer's shapefile.
261            """
262            left, bottom, right, top = box
263            return self.shapetree.find_shapes((left, bottom), (right, top))
264    
265      def SetProjection(self, projection):      def SetProjection(self, projection):
266          """Set the layer's projection"""          """Set the layer's projection"""
267          self.projection = projection          self.projection = projection
268          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
269    
270      def SetFill(self, fill):      def GetClassification(self):
271          """Set the layer's fill color. None means the shapes are not filled"""          return self.__classification
272          self.fill = fill  
273        def SetClassification(self, clazz):
274            """Set the classification to 'clazz'
275    
276            If 'clazz' is None a default classification is created
277            """
278    
279            if clazz is None:
280                self.__classification = classification.Classification()
281            else:
282    
283                # prevent infinite recursion when calling SetLayer()
284                if clazz == self.__classification:
285                    return
286    
287                self.__classification = clazz
288                self.__classification.SetLayer(self)
289    
290          self.changed(LAYER_LEGEND_CHANGED, self)          self.changed(LAYER_LEGEND_CHANGED, self)
291    
292      def SetStroke(self, stroke):      def ClassChanged(self):
293          """Set the layer's stroke color. None means the shapes are not          """Called from the classification object when it has changed."""
         stroked."""  
         self.stroke = stroke  
294          self.changed(LAYER_LEGEND_CHANGED, self)          self.changed(LAYER_LEGEND_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            items.append(self.__classification)
313    
314            return (_("Layer '%s'") % self.Title(), items)
315    

Legend:
Removed from v.6  
changed lines
  Added in v.492

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26