/[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 610 by jonathan, Fri Apr 4 13:56:59 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 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 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_LEGEND_CHANGED, \
19       LAYER_VISIBILITY_CHANGED       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 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, stroke_width = 1, visible = 1):                   fill = Color.Transparent,
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.Transparent if the shapes are
122          stroke -- the stroke color or None if the shapes are not stroked                  not filled
123            stroke -- the stroke color or Color.Transparent if the shapes
124                    are not stroked
125          visible -- boolean. If true the layer is visible.          visible -- boolean. If true the layer is visible.
126    
127          colors are expected to be instances of Color class          colors are expected to be instances of Color class
128          """          """
129          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title, visible = visible)
130          self.filename = filename  
131            # Make the filename absolute. The filename will be
132            # interpreted relative to that anyway, but when saving a
133            # session we need to compare absolute paths and it's usually
134            # safer to always work with absolute paths.
135            self.filename = os.path.abspath(filename)
136    
137          self.projection = projection          self.projection = projection
         self.fill = fill  
         self.stroke = stroke  
         self.stroke_width = stroke_width  
138          self.shapefile = None          self.shapefile = None
139          self.shapetree = None          self.shapetree = None
140          self.open_shapefile()          self.open_shapefile()
# Line 131  class Layer(BaseLayer): Line 144  class Layer(BaseLayer):
144          self.shapetable = Table(filename)          self.shapetable = Table(filename)
145          self.table = self.shapetable          self.table = self.shapetable
146    
147            #
148            # this is really important so that when the classification class
149            # tries to set its parent layer the variable will exist
150            #
151            self.__classification = None
152            self.__setClassLock = False
153    
154    
155            self.SetClassification(None)
156    
157            self.__classification.SetDefaultLineColor(stroke)
158            self.__classification.SetDefaultLineWidth(lineWidth)
159            self.__classification.SetDefaultFill(fill)
160            self.__classification.SetLayer(self)
161    
162            self.UnsetModified()
163    
164      def open_shapefile(self):      def open_shapefile(self):
165          if self.shapefile is None:          if self.shapefile is None:
166              self.shapefile = shapelib.ShapeFile(self.filename)              self.shapefile = shapelib.ShapeFile(self.filename)
167              numshapes, shapetype, mins, maxs = self.shapefile.info()              numshapes, shapetype, mins, maxs = self.shapefile.info()
168              self.numshapes = numshapes              self.numshapes = numshapes
169              self.shapetype = shapelib_shapetypes[shapetype]              self.shapetype = shapelib_shapetypes[shapetype]
170              self.bbox = mins[:2] + maxs[:2]  
171              #print "building tree for", self.filename, "..."              # if there are shapes, set the bbox accordinly. Otherwise
172              self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2, 0)              # set it to None.
173              #print "done"              if self.numshapes:
174                    self.bbox = mins[:2] + maxs[:2]
175                else:
176                    self.bbox = None
177    
178                # estimate a good depth for the quad tree. Each depth
179                # multiplies the number of nodes by four, therefore we
180                # basically take the base 4 logarithm of the number of
181                # shapes.
182                if self.numshapes < 4:
183                    maxdepth = 1
184                else:
185                    maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
186    
187                self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
188                                                 maxdepth)
189    
190        def Destroy(self):
191            BaseLayer.Destroy(self)
192            if self.shapefile is not None:
193                self.shapefile.close()
194                self.shapefile = None
195                self.shapetree = None
196            self.SetClassification(None)
197            self.table.Destroy()
198    
199      def BoundingBox(self):      def BoundingBox(self):
200          """Return the bounding box of the layer's shapes in their default          """Return the layer's bounding box in the intrinsic coordinate system.
201          coordinate system"""  
202            If the layer has no shapes, return None.
203            """
204            # The bbox will be set by open_shapefile just as we need it
205            # here.
206          self.open_shapefile()          self.open_shapefile()
207          return self.bbox          return self.bbox
208    
209      def LatLongBoundingBox(self):      def LatLongBoundingBox(self):
210          """Return the layer's bounding box in lat/long coordinates"""          """Return the layer's bounding box in lat/long coordinates.
211          llx, lly, urx, ury = self.BoundingBox()  
212          if self.projection is not None:          Return None, if the layer doesn't contain any shapes.
213              llx, lly = self.projection.Inverse(llx, lly)          """
214              urx, ury = self.projection.Inverse(urx, ury)          bbox = self.BoundingBox()
215          return llx, lly, urx, ury          if bbox is not None:
216                llx, lly, urx, ury = bbox
217                if self.projection is not None:
218                    llx, lly = self.projection.Inverse(llx, lly)
219                    urx, ury = self.projection.Inverse(urx, ury)
220                return llx, lly, urx, ury
221            else:
222                return None
223    
224        def GetFieldType(self, fieldName):
225            self.open_shapefile()
226            info = self.table.field_info_by_name(fieldName)
227            if info is not None:
228                return info[0]
229            else:
230                return None
231    
232      def NumShapes(self):      def NumShapes(self):
233          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
# Line 172  class Layer(BaseLayer): Line 245  class Layer(BaseLayer):
245          """Return the shape with index index"""          """Return the shape with index index"""
246          self.open_shapefile()          self.open_shapefile()
247          shape = self.shapefile.read_object(index)          shape = self.shapefile.read_object(index)
248    
249          if self.shapetype == SHAPETYPE_POINT:          if self.shapetype == SHAPETYPE_POINT:
250              points = shape.vertices()              points = shape.vertices()
251          else:          else:
# Line 180  class Layer(BaseLayer): Line 254  class Layer(BaseLayer):
254              points = []              points = []
255              for x, y in poly:              for x, y in poly:
256                  points.append((x, y))                  points.append((x, y))
257    
258          return Shape(points)          return Shape(points)
259    
260      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
# Line 189  class Layer(BaseLayer): Line 264  class Layer(BaseLayer):
264          system used by the layer's shapefile.          system used by the layer's shapefile.
265          """          """
266          left, bottom, right, top = box          left, bottom, right, top = box
267          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  
268    
269      def SetProjection(self, projection):      def SetProjection(self, projection):
270          """Set the layer's projection"""          """Set the layer's projection"""
271          self.projection = projection          self.projection = projection
272          self.changed(LAYER_PROJECTION_CHANGED, self)          self.changed(LAYER_PROJECTION_CHANGED, self)
273    
274      def SetFill(self, fill):      def GetClassification(self):
275          """Set the layer's fill color. None means the shapes are not filled"""          return self.__classification
276          self.fill = fill  
277          self.changed(LAYER_LEGEND_CHANGED, self)      def SetClassification(self, clazz):
278            """Set the classification to 'clazz'
279      def SetStroke(self, stroke):  
280          """Set the layer's stroke color. None means the shapes are not          If 'clazz' is None a default classification is created
281          stroked."""          """
282          self.stroke = stroke  
283          self.changed(LAYER_LEGEND_CHANGED, self)          # prevent infinite recursion when calling SetLayer()
284            if self.__setClassLock: return
285      def SetStrokeWidth(self, width):  
286          """Set the layer's stroke width."""          self.__setClassLock = True
287          self.stroke_width = width  
288          self.changed(LAYER_LEGEND_CHANGED, self)          if clazz is None:
289                if self.__classification is not None:
290                    self.__classification.SetLayer(None)
291                self.__classification = classification.Classification()
292            else:
293                self.__classification = clazz
294                try:
295                    self.__classification.SetLayer(self)
296                except ValueError:
297                    self.__setClassLock = False
298                    raise ValueError
299    
300            self.changed(LAYER_CHANGED, self)
301    
302            self.__setClassLock = False
303    
304        def ClassChanged(self):
305            """Called from the classification object when it has changed."""
306            self.changed(LAYER_CHANGED, self)
307    
308        def TreeInfo(self):
309            items = []
310    
311            if self.Visible():
312                items.append(_("Shown"))
313            else:
314                items.append(_("Hidden"))
315            items.append(_("Shapes: %d") % self.NumShapes())
316    
317            bbox = self.LatLongBoundingBox()
318            if bbox is not None:
319                items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
320            else:
321                items.append(_("Extent (lat-lon):"))
322            items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
323    
324            items.append(self.__classification)
325    
326            return (_("Layer '%s'") % self.Title(), items)
327    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26