/[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 701 by bh, Thu Apr 17 16:18:48 2003 UTC revision 839 by bh, Tue May 6 15:54:18 2003 UTC
# Line 8  Line 8 
8    
9  __version__ = "$Revision$"  __version__ = "$Revision$"
10    
 import os  
11  from math import log, ceil  from math import log, ceil
12    
13  from Thuban import _  from Thuban import _
# Line 22  from color import Color Line 21  from color import Color
21    
22  import classification  import classification
23    
 from table import Table  
   
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 33  class Shape: Line 31  class Shape:
31      def __init__(self, points):      def __init__(self, points):
32          self.points = points          self.points = points
33          #self.compute_bbox()          #self.compute_bbox()
34            self.bbox = None
35    
36      def compute_bbox(self):      def compute_bbox(self):
37            if self.bbox is not None:
38                return self.bbox
39    
40          xs = []          xs = []
41          ys = []          ys = []
42          for x, y in self.points:          for x, y in self.points:
# Line 45  class Shape: Line 47  class Shape:
47          self.urx = max(xs)          self.urx = max(xs)
48          self.ury = max(ys)          self.ury = max(ys)
49    
50            self.bbox = (self.llx, self.lly, self.urx, self.ury)
51    
52            return self.bbox
53    
54      def Points(self):      def Points(self):
55          return self.points          return self.points
56    
# Line 68  class BaseLayer(TitledObject, Modifiable Line 74  class BaseLayer(TitledObject, Modifiable
74    
75      """Base class for the layers."""      """Base class for the layers."""
76    
77      def __init__(self, title, visible = 1):      def __init__(self, title, visible = True):
78          """Initialize the layer.          """Initialize the layer.
79    
80          title -- the title          title -- the title
# Line 104  class Layer(BaseLayer): Line 110  class Layer(BaseLayer):
110          LAYER_PROJECTION_CHANGED -- the projection has changed.          LAYER_PROJECTION_CHANGED -- the projection has changed.
111      """      """
112    
113      def __init__(self, title, filename, projection = None,      def __init__(self, title, data, projection = None,
114                   fill = Color.Transparent,                   fill = Color.Transparent,
115                   stroke = Color.Black,                   stroke = Color.Black,
116                   lineWidth = 1,                   lineWidth = 1,
117                   visible = 1):                   visible = True):
118          """Initialize the layer.          """Initialize the layer.
119    
120          title -- the title          title -- the title
121          filename -- the name of the shapefile          data -- datastore object for the shape data shown by the layer
122          projection -- the projection object. Its Inverse method is          projection -- the projection object. Its Inverse method is
123                 assumed to map the layer's coordinates to lat/long                 assumed to map the layer's coordinates to lat/long
124                 coordinates                 coordinates
# Line 126  class Layer(BaseLayer): Line 132  class Layer(BaseLayer):
132          """          """
133          BaseLayer.__init__(self, title, visible = visible)          BaseLayer.__init__(self, title, visible = visible)
134    
         # Make the filename absolute. The filename will be  
         # interpreted relative to that anyway, but when saving a  
         # session we need to compare absolute paths and it's usually  
         # safer to always work with absolute paths.  
         self.filename = os.path.abspath(filename)  
   
135          self.projection = projection          self.projection = projection
         self.shapefile = None  
         self.shapetree = None  
         self.open_shapefile()  
         # shapetable is the table associated with the shapefile, while  
         # table is the default table used to look up attributes for  
         # display  
         self.shapetable = Table(filename)  
         self.table = self.shapetable  
136    
137          #          #
138          # this is really important so that when the classification class          # this is really important so that when the classification class
139          # tries to set its parent layer the variable will exist          # tries to set its parent layer the variable will exist
140          #          #
141          self.__classification = None          self.__classification = None
142          self.__setClassLock = False          self.__setClassLock = False
143    
144            self.SetShapeStore(data)
145    
146          self.SetClassification(None)          self.SetClassification(None)
147    
# Line 159  class Layer(BaseLayer): Line 152  class Layer(BaseLayer):
152    
153          self.UnsetModified()          self.UnsetModified()
154    
     def open_shapefile(self):  
         if self.shapefile is None:  
             self.shapefile = shapelib.ShapeFile(self.filename)  
             numshapes, shapetype, mins, maxs = self.shapefile.info()  
             self.numshapes = numshapes  
             self.shapetype = shapelib_shapetypes[shapetype]  
   
             # if there are shapes, set the bbox accordinly. Otherwise  
             # set it to None.  
             if self.numshapes:  
                 self.bbox = mins[:2] + maxs[:2]  
             else:  
                 self.bbox = None  
   
             # estimate a good depth for the quad tree. Each depth  
             # multiplies the number of nodes by four, therefore we  
             # basically take the base 4 logarithm of the number of  
             # shapes.  
             if self.numshapes < 4:  
                 maxdepth = 1  
             else:  
                 maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))  
155    
156              self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,      def SetShapeStore(self, store):
157                                               maxdepth)          self.store = store
158            self.shapefile = self.store.Shapefile()
159            self.shapetable = self.store.Table()
160            self.filename = self.store.filename
161            self.table = self.shapetable
162    
163            numshapes, shapetype, mins, maxs = self.shapefile.info()
164            self.numshapes = numshapes
165            self.shapetype = shapelib_shapetypes[shapetype]
166    
167            # if there are shapes, set the bbox accordingly. Otherwise
168            # set it to None.
169            if self.numshapes:
170                self.bbox = mins[:2] + maxs[:2]
171            else:
172                self.bbox = None
173    
174            # estimate a good depth for the quad tree. Each depth
175            # multiplies the number of nodes by four, therefore we
176            # basically take the base 4 logarithm of the number of
177            # shapes.
178            if self.numshapes < 4:
179                maxdepth = 1
180            else:
181                maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
182    
183            self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
184                                             maxdepth)
185            if self.__classification is not None:
186                fieldname = self.__classification.GetField()
187                if fieldname is not None and \
188                   not self.store.Table().HasColumn(fieldname):
189                    self.SetClassification(None)
190            self.changed(LAYER_CHANGED, self)
191    
192        def ShapeStore(self):
193            return self.store
194    
195      def Destroy(self):      def Destroy(self):
196          BaseLayer.Destroy(self)          BaseLayer.Destroy(self)
         if self.shapefile is not None:  
             self.shapefile.close()  
             self.shapefile = None  
             self.shapetree = None  
197          self.SetClassification(None)          self.SetClassification(None)
         self.table.Destroy()  
198    
199      def BoundingBox(self):      def BoundingBox(self):
200          """Return the layer's bounding box in the intrinsic coordinate system.          """Return the layer's bounding box in the intrinsic coordinate system.
# Line 216  class Layer(BaseLayer): Line 218  class Layer(BaseLayer):
218          else:          else:
219              return None              return None
220    
221      def GetFieldType(self, fieldName):      def ShapesBoundingBox(self, shapes):
222          info = self.table.field_info_by_name(fieldName)          """Return a bounding box in lat/long coordinates for the given
223          if info is not None:          list of shape ids.
224              return info[0]  
225            If shapes is None or empty, return None.
226            """
227    
228            if shapes is None or len(shapes) == 0: return None
229    
230            llx = []
231            lly = []
232            urx = []
233            ury = []
234    
235            if self.projection is not None:
236                inverse = lambda x, y: self.projection.Inverse(x, y)
237          else:          else:
238              return None              inverse = lambda x, y: (x, y)
239    
240            for id in shapes:
241                left, bottom, right, top = self.Shape(id).compute_bbox()
242    
243                left, bottom = inverse(left, bottom)
244                right, top   = inverse(right, top)
245    
246                llx.append(left)
247                lly.append(bottom)
248                urx.append(right)
249                ury.append(top)
250    
251            return (min(llx), min(lly), max(urx), max(ury))
252    
253        def GetFieldType(self, fieldName):
254            if self.table.HasColumn(fieldName):
255                return self.table.Column(fieldName).type
256            return None
257    
258      def NumShapes(self):      def NumShapes(self):
259          """Return the number of shapes in the layer"""          """Return the number of shapes in the layer"""
# Line 251  class Layer(BaseLayer): Line 283  class Layer(BaseLayer):
283      def ShapesInRegion(self, box):      def ShapesInRegion(self, box):
284          """Return the ids of the shapes that overlap the box.          """Return the ids of the shapes that overlap the box.
285    
286          Box is a tuple (left, bottom, right, top) in the coordinate          Box is a tuple (left, bottom, right, top) in unprojected coordinates.
         system used by the layer's shapefile.  
287          """          """
288          left, bottom, right, top = box          left, bottom, right, top = box
289    
290            if self.projection is not None:
291                left,  bottom = self.projection.Forward(left, bottom)
292                right, top    = self.projection.Forward(right, top)
293    
294          return self.shapetree.find_shapes((left, bottom), (right, top))          return self.shapetree.find_shapes((left, bottom), (right, top))
295    
296        def GetProjection(self):
297            return self.projection
298    
299      def SetProjection(self, projection):      def SetProjection(self, projection):
300          """Set the layer's projection"""          """Set the layer's projection"""
301          self.projection = projection          self.projection = projection
# Line 312  class Layer(BaseLayer): Line 351  class Layer(BaseLayer):
351              items.append(_("Extent (lat-lon):"))              items.append(_("Extent (lat-lon):"))
352          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])          items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
353    
354            if self.projection and len(self.projection.params) > 0:
355                items.append((_("Projection"),
356                            [str(param) for param in self.projection.params]))
357    
358          items.append(self.__classification)          items.append(self.__classification)
359    
360          return (_("Layer '%s'") % self.Title(), items)          return (_("Layer '%s'") % self.Title(), items)
361    
362    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26