/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/data.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/data.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1535 by bh, Fri Aug 1 14:27:13 2003 UTC revision 2605 by jan, Wed Apr 27 11:04:56 2005 UTC
# Line 1  Line 1 
1  # Copyright (C) 2003 by Intevation GmbH  # Copyright (C) 2003, 2005 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 7  Line 7 
7    
8  """Data source abstractions"""  """Data source abstractions"""
9    
10    from __future__ import generators
11    
12  __version__ = "$Revision$"  __version__ = "$Revision$"
13  # $Source$  # $Source$
14  # $Id$  # $Id$
# Line 32  shapelib_shapetypes = {shapelib.SHPT_POL Line 34  shapelib_shapetypes = {shapelib.SHPT_POL
34                         shapelib.SHPT_ARC: SHAPETYPE_ARC,                         shapelib.SHPT_ARC: SHAPETYPE_ARC,
35                         shapelib.SHPT_POINT: SHAPETYPE_POINT}                         shapelib.SHPT_POINT: SHAPETYPE_POINT}
36    
37    #
38    # Raw shape data formats
39    #
40    
41  class Shape:  # Raw data is the same as that returned by the points method.
42    RAW_PYTHON = "RAW_PYTHON"
43    
44      """Represent one shape"""  # Raw data is a shapefile. The Shape object will use the shapeid as the
45    # raw data.
46    RAW_SHAPEFILE = "RAW_SHAPEFILE"
47    
48      def __init__(self, points):  # Raw data in well-known text format
49          self.points = points  RAW_WKT = "RAW_WKT"
         #self.compute_bbox()  
         self.bbox = None  
50    
     def compute_bbox(self):  
         if self.bbox is not None:  
             return self.bbox  
51    
52    class ShapefileShape:
53    
54        """Represent one shape of a shapefile"""
55    
56        def __init__(self, shapefile, shapeid):
57            self.shapefile = shapefile
58            self.shapeid = shapeid
59    
60        def compute_bbox(self):
61            """
62            Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
63            """
64          xs = []          xs = []
65          ys = []          ys = []
66          for x, y in self.points:          for part in self.Points():
67              xs.append(x)              for x, y in part:
68              ys.append(y)                  xs.append(x)
69          self.llx = min(xs)                  ys.append(y)
70          self.lly = min(ys)          return (min(xs), min(ys), max(xs), max(ys))
         self.urx = max(xs)  
         self.ury = max(ys)  
   
         self.bbox = (self.llx, self.lly, self.urx, self.ury)  
71    
72          return self.bbox      def ShapeID(self):
73            return self.shapeid
74    
75      def Points(self):      def Points(self):
76          return self.points          """Return the coordinates of the shape as a list of lists of pairs"""
77            shape = self.shapefile.read_object(self.shapeid)
78            points = shape.vertices()
79            if self.shapefile.info()[1] == shapelib.SHPT_POINT:
80                points = [points]
81            return points
82    
83        def RawData(self):
84            """Return the shape id to use with the shapefile"""
85            return self.shapeid
86    
87        def Shapefile(self):
88            """Return the shapefile object"""
89            return self.shapefile
90    
91    
92  class ShapeTable(transientdb.AutoTransientTable):  class ShapeTable(transientdb.AutoTransientTable):
# Line 88  class ShapeTable(transientdb.AutoTransie Line 112  class ShapeTable(transientdb.AutoTransie
112          """Return a tuple containing the shapestore"""          """Return a tuple containing the shapestore"""
113          return (self.store(),)          return (self.store(),)
114    
115    # XXX: (this statement should be kept in mind when re-engeneering)
116    #
117    # From a desing POV it was wrong to distinguish between table and
118    # shapestore.  In hindsight the only reason for doing so was that the
119    # shapelib has different objects for the shapefile(s) and the dbf file,
120    # which of course matches the way the data is organized into different
121    # files.  So the distinction between shapestore and table is an artifact
122    # of the shapefile format.  When we added the postgis support we should
123    # have adopted the table interface for the entire shape store, making the
124    # geometry data an additional column for those shape stores that don't
125    # store the geometries in columns in the first place.
126    
127    class FileShapeStore:
128    
129        """The base class to derive any file-based ShapeStore from.
130    
131        This class contains all information that is needed by a
132        loader routine to actually load the shapestore.
133        This essentially means that the class contains all required information
134        to save the shapestore specification (i.e. in a .thuban file).
135        """
136    
137        def __init__(self, filename, sublayer_name = None):
138            """Initialize the base class with main parameters.
139    
140            filename  -- the source filename.
141                         This filename will be converted to an absolute filename.
142                         The filename will be interpreted relative to the .thuban file anyway,
143                         but when saving a session we need to compare absolute paths
144                         and it's usually safer to always work with absolute paths.
145            sublayer_name -- a string representing a layer within the file shape store.
146                         Some file formats support to contain several layers, or
147                         at least the ogr library says so.
148                         For those filetypes who don't, the sublayer_name can be ignored
149                         and by default it is None.
150            """
151            self._filename = os.path.abspath(filename)
152            self._sublayer_name = sublayer_name
153    
154        def FileName(self):
155            """Return the filename used to open the shapestore.
156    
157            The filename can only be set via __init__ method.
158            """
159            return self._filename
160    
161        def FileType(self):
162            """Return the filetype.
163    
164            The filetype has to be set in all derived classes.
165            It must be string.
166            Known and used types are: "shapefile"
167            """
168            raise NotImplementedError
169    
170        def SublayerName(self):
171            """Return the sublayer_name.
172    
173  class ShapefileStore:          This could be None if the shapestore type only supports a single
174            layer.
175            """
176            return self._sublayer_name
177    
178        # Design/Implementation note:
179        # It is not a good idea to have a implementation for a
180        # "setBoundingBox" or BoundingBox in this base class.
181        # In future this data might change during
182        # a Thuban session and thus can not be kept statically here.
183        # It is expected that for many derived classes the bbox must
184        # be retrieved each time anew.
185    
186        def BoundingBox(self):
187            """Return the bounding box of the shapes in the shape store.
188    
189            The coordinate system used is whatever was used in the shape store.
190            If the shape store is empty, return None.
191            """
192            raise NotImplementedError
193    
194    class ShapefileStore(FileShapeStore):
195    
196      """Combine a shapefile and the corresponding DBF file into one object"""      """Combine a shapefile and the corresponding DBF file into one object"""
197    
198      def __init__(self, session, filename):      def __init__(self, session, filename):
199          # Make the filename absolute. The filename will be          FileShapeStore.__init__(self, filename)
         # 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)  
200    
         self.shapefile = shapelib.ShapeFile(self.filename)  
201          self.dbftable = table.DBFTable(filename)          self.dbftable = table.DBFTable(filename)
202          self.table = ShapeTable(self, session.TransientDB(), self.dbftable)          self._table = ShapeTable(self, session.TransientDB(), self.dbftable)
203            self._bbox = None
204            self._open_shapefile()
205    
206        def _open_shapefile(self):
207            self.shapefile = shapelib.ShapeFile(self.FileName())
208          self.numshapes, shapetype, mins, maxs = self.shapefile.info()          self.numshapes, shapetype, mins, maxs = self.shapefile.info()
209          if self.numshapes:          if self.numshapes:
210              self.bbox = mins[:2] + maxs[:2]              self._bbox = mins[:2] + maxs[:2]
211          else:          else:
212              self.bbox = None              self._bbox = None
213          self.shapetype = shapelib_shapetypes[shapetype]          self.shapetype = shapelib_shapetypes[shapetype]
214    
215          # estimate a good depth for the quad tree. Each depth multiplies          # estimate a good depth for the quad tree. Each depth multiplies
# Line 123  class ShapefileStore: Line 224  class ShapefileStore:
224                                           maxdepth)                                           maxdepth)
225    
226      def Table(self):      def Table(self):
227          """Return the table containing the attribute data"""          """Return the table containing the attribute data."""
228          return self.table          return self._table
229    
230      def Shapefile(self):      def Shapefile(self):
231          """Return the shapefile object"""          """Return the shapefile object"""
232          return self.shapefile          return self.shapefile
233    
     def FileName(self):  
         """Return the filename used to open the shapefile"""  
         return self.filename  
   
234      def FileType(self):      def FileType(self):
235          """Return the filetype. This is always the string 'shapefile'"""          """Return the filetype. This is always the string 'shapefile'"""
236          return "shapefile"          return "shapefile"
# Line 145  class ShapefileStore: Line 242  class ShapefileStore:
242          """          """
243          return self.shapetype          return self.shapetype
244    
245        def RawShapeFormat(self):
246            """Return the raw data format of the shape data, i.e. RAW_SHAPEFILE"""
247            return RAW_SHAPEFILE
248    
249      def NumShapes(self):      def NumShapes(self):
250          """Return the number of shapes in the shape store"""          """Return the number of shapes in the shapefile"""
251          return self.numshapes          return self.numshapes
252    
253      def Dependencies(self):      def Dependencies(self):
# Line 164  class ShapefileStore: Line 265  class ShapefileStore:
265          return None          return None
266    
267      def BoundingBox(self):      def BoundingBox(self):
268          """Return the bounding box of the shapes in the shapestore.          """Return the bounding box of the shapes in the shapefile.
269    
270          The coordinate system used is whatever was used in the shapefile.          The coordinate system used is whatever was used in the shapefile.
271          If the shapefile is empty, return None.          If the shapefileis empty, return None.
272          """          """
273          return self.bbox          return self._bbox
274    
275      def ShapesInRegion(self, box):      def ShapesInRegion(self, bbox):
276          """Return the ids of the shapes that overlap the box.          """Return an iterable over the shapes that overlap the bounding box.
277    
278          Box is a tuple (left, bottom, right, top) in the coordinate          The bbox parameter should be the bounding box as a tuple in the
279          system used used in the shapefile.          form (minx, miny, maxx, maxy) in the coordinate system of the
280          """          shapefile.
281          left, bottom, right, top = box          """
282          return self.shapetree.find_shapes((left, bottom), (right, top))          # Bind a few globals to locals to make it a bit faster
283            cls = ShapefileShape
284            shapefile = self.shapefile
285    
286            left, bottom, right, top = bbox
287            for i in self.shapetree.find_shapes((left, bottom), (right, top)):
288                yield cls(shapefile, i)
289    
290        def AllShapes(self):
291            """Return an iterable over the shapes in the shapefile."""
292            for i in xrange(self.NumShapes()):
293                yield ShapefileShape(self.shapefile, i)
294    
295      def Shape(self, index):      def Shape(self, index):
296          """Return the shape with index index"""          """Return the shape with index index"""
297          shape = self.shapefile.read_object(index)          return ShapefileShape(self.shapefile, index)
   
         if self.ShapeType() == SHAPETYPE_POINT:  
             points = shape.vertices()  
         else:  
             #for poly in shape.vertices():  
             poly = shape.vertices()[0]  
             points = []  
             for x, y in poly:  
                 points.append((x, y))  
   
         return Shape(points)  
   
298    
299    
300  class DerivedShapeStore:  class DerivedShapeStore:
# Line 248  class DerivedShapeStore: Line 348  class DerivedShapeStore:
348          """          """
349          return self.shapestore.ShapesInRegion(bbox)          return self.shapestore.ShapesInRegion(bbox)
350    
351        def AllShapes(self):
352            """Return an iterable over the shapes in the shapefile.
353    
354            This method is simply delegated to the shapestore the
355            DerivedShapeStore was instantiated with.
356            """
357            return self.shapestore.AllShapes()
358    
359      def ShapeType(self):      def ShapeType(self):
360          """Return the type of the shapes in the layer.          """Return the type of the shapes in the layer.
361    
# Line 256  class DerivedShapeStore: Line 364  class DerivedShapeStore:
364          """          """
365          return self.shapestore.ShapeType()          return self.shapestore.ShapeType()
366    
367        def RawShapeFormat(self):
368            """Return the raw data format of the shapes.
369    
370            This method is simply delegated to the shapestore the
371            DerivedShapeStore was instantiated with.
372            """
373            return self.shapestore.RawShapeFormat()
374    
375      def NumShapes(self):      def NumShapes(self):
376          """Return the number of shapes in the shapestore."""          """Return the number of shapes in the shapestore."""
377          return self.shapestore.NumShapes()          return self.shapestore.NumShapes()

Legend:
Removed from v.1535  
changed lines
  Added in v.2605

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26