/[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 701 by bh, Thu Apr 17 16:18:48 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    import os
12    from math import log, ceil
13    
14    from Thuban import _
15    
16  import shapelib, shptree  import shapelib, shptree
17    
18  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
19       LAYER_VISIBILITY_CHANGED       LAYER_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 97  class Layer(BaseLayer): Line 102  class Layer(BaseLayer):
102    
103          TITLE_CHANGED -- The title has changed.          TITLE_CHANGED -- The title has changed.
104          LAYER_PROJECTION_CHANGED -- the projection has changed.          LAYER_PROJECTION_CHANGED -- the projection has changed.
         LAYER_LEGEND_CHANGED -- the fill or stroke attributes have changed  
   
105      """      """
106    
107      def __init__(self, title, filename, projection = None,      def __init__(self, title, filename, projection = None,
108                   fill = None, stroke = _black, stroke_width = 1, visible = 1):                   fill = Color.Transparent,
109                     stroke = Color.Black,
110                     lineWidth = 1,
111                     visible = 1):
112          """Initialize the layer.          """Initialize the layer.
113    
114          title -- the title          title -- the title
# Line 110  class Layer(BaseLayer): Line 116  class Layer(BaseLayer):
116          projection -- the projection object. Its Inverse method is          projection -- the projection object. Its Inverse method is
117                 assumed to map the layer's coordinates to lat/long                 assumed to map the layer's coordinates to lat/long
118                 coordinates                 coordinates
119          fill -- the fill color or None if the shapes are not filled          fill -- the fill color or Color.Transparent if the shapes are
120          stroke -- the stroke color or None if the shapes are not stroked                  not filled
121            stroke -- the stroke color or Color.Transparent if the shapes
122                    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  
         self.stroke_width = stroke_width  
136          self.shapefile = None          self.shapefile = None
137          self.shapetree = None          self.shapetree = None
138          self.open_shapefile()          self.open_shapefile()
# Line 131  class Layer(BaseLayer): Line 142  class Layer(BaseLayer):
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            self.__setClassLock = False
151    
152    
153            self.SetClassification(None)
154    
155            self.__classification.SetDefaultLineColor(stroke)
156            self.__classification.SetDefaultLineWidth(lineWidth)
157            self.__classification.SetDefaultFill(fill)
158            self.__classification.SetLayer(self)
159    
160            self.UnsetModified()
161    
162      def open_shapefile(self):      def open_shapefile(self):
163          if self.shapefile is None:          if self.shapefile is None:
164              self.shapefile = shapelib.ShapeFile(self.filename)              self.shapefile = shapelib.ShapeFile(self.filename)
165              numshapes, shapetype, mins, maxs = self.shapefile.info()              numshapes, shapetype, mins, maxs = self.shapefile.info()
166              self.numshapes = numshapes              self.numshapes = numshapes
167              self.shapetype = shapelib_shapetypes[shapetype]              self.shapetype = shapelib_shapetypes[shapetype]
168              self.bbox = mins[:2] + maxs[:2]  
169              #print "building tree for", self.filename, "..."              # if there are shapes, set the bbox accordinly. Otherwise
170              self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2, 0)              # set it to None.
171              #print "done"              if self.numshapes:
172                    self.bbox = mins[:2] + maxs[:2]
173                else:
174                    self.bbox = None
175    
176                # estimate a good depth for the quad tree. Each depth
177                # multiplies the number of nodes by four, therefore we
178                # basically take the base 4 logarithm of the number of
179                # shapes.
180                if self.numshapes < 4:
181                    maxdepth = 1
182                else:
183                    maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
184    
185                self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
186                                                 maxdepth)
187    
188        def Destroy(self):
189            BaseLayer.Destroy(self)
190            if self.shapefile is not None:
191                self.shapefile.close()
192                self.shapefile = None
193                self.shapetree = None
194            self.SetClassification(None)
195            self.table.Destroy()
196    
197      def BoundingBox(self):      def BoundingBox(self):
198          """Return the bounding box of the layer's shapes in their default          """Return the layer's bounding box in the intrinsic coordinate system.
199          coordinate system"""  
200          self.open_shapefile()          If the layer has no shapes, return None.
201            """
202          return self.bbox          return self.bbox
203    
204      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
205          """Return the layer's bounding box in lat/long coordinates"""          """Return the layer's bounding box in lat/long coordinates.
206          llx, lly, urx, ury = self.BoundingBox()  
207          if self.projection is not None:          Return None, if the layer doesn't contain any shapes.
208              llx, lly = self.projection.Inverse(llx, lly)          """
209              urx, ury = self.projection.Inverse(urx, ury)          bbox = self.BoundingBox()
210          return llx, lly, urx, ury          if bbox is not None:
211                llx, lly, urx, ury = bbox
212                if self.projection is not None:
213                    llx, lly = self.projection.Inverse(llx, lly)
214                    urx, ury = self.projection.Inverse(urx, ury)
215                return llx, lly, urx, ury
216            else:
217                return None
218    
219        def GetFieldType(self, fieldName):
220            info = self.table.field_info_by_name(fieldName)
221            if info is not None:
222                return info[0]
223            else:
224                return None
225    
226      def NumShapes(self):      def NumShapes(self):
227          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
         self.open_shapefile()  
228          return self.numshapes          return self.numshapes
229    
230      def ShapeType(self):      def ShapeType(self):
231          """Return the type of the shapes in the layer.          """Return the type of the shapes in the layer.
232          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.          This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
233          """          """
         self.open_shapefile()  
234          return self.shapetype          return self.shapetype
235    
236      def Shape(self, index):      def Shape(self, index):
237          """Return the shape with index index"""          """Return the shape with index index"""
         self.open_shapefile()  
238          shape = self.shapefile.read_object(index)          shape = self.shapefile.read_object(index)
239    
240          if self.shapetype == SHAPETYPE_POINT:          if self.shapetype == SHAPETYPE_POINT:
241              points = shape.vertices()              points = shape.vertices()
242          else:          else:
# Line 180  class Layer(BaseLayer): Line 245  class Layer(BaseLayer):
245              points = []              points = []
246              for x, y in poly:              for x, y in poly:
247                  points.append((x, y))                  points.append((x, y))
248    
249          return Shape(points)          return Shape(points)
250    
251      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
# Line 189  class Layer(BaseLayer): Line 255  class Layer(BaseLayer):
255          system used by the layer's shapefile.          system used by the layer's shapefile.
256          """          """
257          left, bottom, right, top = box          left, bottom, right, top = box
258          import time          return self.shapetree.find_shapes((left, bottom), (right, top))
         start = time.time()  
         ids = self.shapetree.find_shapes((left, bottom), (right, top))  
         print "ShapesInRegion", time.time() - start  
         return ids  
259    
260      def SetProjection(self, projection):      def SetProjection(self, projection):
261          """Set the layer's projection"""          """Set the layer's projection"""
262          self.projection = projection          self.projection = projection
263          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
264    
265      def SetFill(self, fill):      def GetClassification(self):
266          """Set the layer's fill color. None means the shapes are not filled"""          return self.__classification
267          self.fill = fill  
268          self.changed(LAYER_LEGEND_CHANGED, self)      def SetClassification(self, clazz):
269            """Set the classification to 'clazz'
270      def SetStroke(self, stroke):  
271          """Set the layer's stroke color. None means the shapes are not          If 'clazz' is None a default classification is created
272          stroked."""          """
273          self.stroke = stroke  
274          self.changed(LAYER_LEGEND_CHANGED, self)          # prevent infinite recursion when calling SetLayer()
275            if self.__setClassLock: return
276      def SetStrokeWidth(self, width):  
277          """Set the layer's stroke width."""          self.__setClassLock = True
278          self.stroke_width = width  
279          self.changed(LAYER_LEGEND_CHANGED, self)          if clazz is None:
280                if self.__classification is not None:
281                    self.__classification.SetLayer(None)
282                self.__classification = classification.Classification()
283            else:
284                self.__classification = clazz
285                try:
286                    self.__classification.SetLayer(self)
287                except ValueError:
288                    self.__setClassLock = False
289                    raise ValueError
290    
291            self.changed(LAYER_CHANGED, self)
292    
293            self.__setClassLock = False
294    
295        def ClassChanged(self):
296            """Called from the classification object when it has changed."""
297            self.changed(LAYER_CHANGED, self)
298    
299        def TreeInfo(self):
300            items = []
301    
302            if self.Visible():
303                items.append(_("Shown"))
304            else:
305                items.append(_("Hidden"))
306            items.append(_("Shapes: %d") % self.NumShapes())
307    
308            bbox = self.LatLongBoundingBox()
309            if bbox is not None:
310                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
311            else:
312                items.append(_("Extent (lat-lon):"))
313            items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
314    
315            items.append(self.__classification)
316    
317            return (_("Layer '%s'") % self.Title(), items)
318    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26