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

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/Model/layer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 791 - (hide annotations)
Wed Apr 30 12:26:33 2003 UTC (21 years, 10 months ago) by jan
Original Path: trunk/thuban/Thuban/Model/layer.py
File MIME type: text/x-python
File size: 9637 byte(s)
(Layer.SetShapeStore): Fixed a bug: don't set the Classification to
None if the classfication field is None (ie only a DEFAULT).

1 bh 701 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4 jonathan 412 # Jonathan Coles <[email protected]>
5 bh 6 #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     __version__ = "$Revision$"
10    
11 bh 171 from math import log, ceil
12    
13 jan 374 from Thuban import _
14    
15 bh 143 import shapelib, shptree
16 bh 6
17 bh 701 from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
18     LAYER_CHANGED
19 bh 6
20     from color import Color
21    
22 jonathan 437 import classification
23 bh 6
24     from base import TitledObject, Modifiable
25    
26 bh 723
27 bh 6 class Shape:
28    
29     """Represent one shape"""
30    
31     def __init__(self, points):
32     self.points = points
33     #self.compute_bbox()
34    
35     def compute_bbox(self):
36     xs = []
37     ys = []
38     for x, y in self.points:
39     xs.append(x)
40     ys.append(y)
41     self.llx = min(xs)
42     self.lly = min(ys)
43     self.urx = max(xs)
44     self.ury = max(ys)
45    
46     def Points(self):
47     return self.points
48    
49    
50    
51     # Shape type constants
52     SHAPETYPE_POLYGON = "polygon"
53     SHAPETYPE_ARC = "arc"
54     SHAPETYPE_POINT = "point"
55    
56     # mapping from shapelib shapetype constants to our constants
57     shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,
58     shapelib.SHPT_ARC: SHAPETYPE_ARC,
59     shapelib.SHPT_POINT: SHAPETYPE_POINT}
60    
61     shapetype_names = {SHAPETYPE_POINT: "Point",
62     SHAPETYPE_ARC: "Arc",
63     SHAPETYPE_POLYGON: "Polygon"}
64    
65     class BaseLayer(TitledObject, Modifiable):
66    
67     """Base class for the layers."""
68    
69 jonathan 771 def __init__(self, title, visible = True):
70 bh 6 """Initialize the layer.
71    
72     title -- the title
73     visible -- boolean. If true the layer is visible.
74     """
75     TitledObject.__init__(self, title)
76     Modifiable.__init__(self)
77     self.visible = visible
78    
79     def Visible(self):
80     """Return true if layer is visible"""
81     return self.visible
82    
83     def SetVisible(self, visible):
84     """Set the layer's visibility."""
85     self.visible = visible
86     self.issue(LAYER_VISIBILITY_CHANGED, self)
87 bh 276
88    
89 bh 6 class Layer(BaseLayer):
90    
91     """Represent the information of one geodata file (currently a shapefile)
92    
93     All children of the layer have the same type.
94    
95     A layer has fill and stroke colors. Colors should be instances of
96     Color. They can also be None, indicating no fill or no stroke.
97    
98     The layer objects send the following events, all of which have the
99     layer object as parameter:
100    
101     TITLE_CHANGED -- The title has changed.
102     LAYER_PROJECTION_CHANGED -- the projection has changed.
103     """
104    
105 bh 723 def __init__(self, title, data, projection = None,
106 jonathan 610 fill = Color.Transparent,
107 jonathan 412 stroke = Color.Black,
108 jonathan 464 lineWidth = 1,
109 jonathan 771 visible = True):
110 bh 6 """Initialize the layer.
111    
112     title -- the title
113 bh 723 data -- datastore object for the shape data shown by the layer
114 bh 6 projection -- the projection object. Its Inverse method is
115     assumed to map the layer's coordinates to lat/long
116     coordinates
117 jonathan 610 fill -- the fill color or Color.Transparent if the shapes are
118     not filled
119     stroke -- the stroke color or Color.Transparent if the shapes
120     are not stroked
121 bh 6 visible -- boolean. If true the layer is visible.
122    
123     colors are expected to be instances of Color class
124     """
125     BaseLayer.__init__(self, title, visible = visible)
126 bh 276
127 bh 6 self.projection = projection
128    
129 jonathan 481 #
130     # this is really important so that when the classification class
131     # tries to set its parent layer the variable will exist
132     #
133 bh 723 self.__classification = None
134 jonathan 529 self.__setClassLock = False
135 jonathan 481
136 bh 723 self.SetShapeStore(data)
137 jonathan 492
138     self.SetClassification(None)
139    
140 jonathan 464 self.__classification.SetDefaultLineColor(stroke)
141     self.__classification.SetDefaultLineWidth(lineWidth)
142 jonathan 412 self.__classification.SetDefaultFill(fill)
143 jonathan 492 self.__classification.SetLayer(self)
144 jonathan 364
145 jonathan 389 self.UnsetModified()
146    
147 bh 6
148 bh 723 def SetShapeStore(self, store):
149     self.store = store
150     self.shapefile = self.store.Shapefile()
151     self.shapetable = self.store.Table()
152     self.filename = self.store.filename
153     self.table = self.shapetable
154 bh 179
155 bh 723 numshapes, shapetype, mins, maxs = self.shapefile.info()
156     self.numshapes = numshapes
157     self.shapetype = shapelib_shapetypes[shapetype]
158 bh 171
159 bh 723 # if there are shapes, set the bbox accordingly. Otherwise
160     # set it to None.
161     if self.numshapes:
162     self.bbox = mins[:2] + maxs[:2]
163     else:
164     self.bbox = None
165 bh 171
166 bh 723 # estimate a good depth for the quad tree. Each depth
167     # multiplies the number of nodes by four, therefore we
168     # basically take the base 4 logarithm of the number of
169     # shapes.
170     if self.numshapes < 4:
171     maxdepth = 1
172     else:
173     maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
174    
175     self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
176     maxdepth)
177     if self.__classification is not None:
178     fieldname = self.__classification.GetField()
179 jan 791 if fieldname is not None and \
180     not self.store.Table().field_info_by_name(fieldname):
181 bh 723 self.SetClassification(None)
182     self.changed(LAYER_CHANGED, self)
183    
184     def ShapeStore(self):
185     return self.store
186    
187 bh 258 def Destroy(self):
188 bh 260 BaseLayer.Destroy(self)
189 jonathan 529 self.SetClassification(None)
190 bh 258
191 bh 6 def BoundingBox(self):
192 bh 179 """Return the layer's bounding box in the intrinsic coordinate system.
193    
194     If the layer has no shapes, return None.
195     """
196 bh 6 return self.bbox
197    
198     def LatLongBoundingBox(self):
199 bh 179 """Return the layer's bounding box in lat/long coordinates.
200 bh 6
201 bh 179 Return None, if the layer doesn't contain any shapes.
202     """
203     bbox = self.BoundingBox()
204     if bbox is not None:
205     llx, lly, urx, ury = bbox
206     if self.projection is not None:
207     llx, lly = self.projection.Inverse(llx, lly)
208     urx, ury = self.projection.Inverse(urx, ury)
209     return llx, lly, urx, ury
210     else:
211     return None
212    
213 jonathan 464 def GetFieldType(self, fieldName):
214     info = self.table.field_info_by_name(fieldName)
215     if info is not None:
216     return info[0]
217     else:
218     return None
219    
220 bh 6 def NumShapes(self):
221     """Return the number of shapes in the layer"""
222     return self.numshapes
223    
224     def ShapeType(self):
225     """Return the type of the shapes in the layer.
226     This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
227     """
228     return self.shapetype
229    
230     def Shape(self, index):
231     """Return the shape with index index"""
232     shape = self.shapefile.read_object(index)
233 jonathan 364
234 bh 6 if self.shapetype == SHAPETYPE_POINT:
235     points = shape.vertices()
236     else:
237     #for poly in shape.vertices():
238     poly = shape.vertices()[0]
239     points = []
240     for x, y in poly:
241 bh 82 points.append((x, y))
242 jonathan 364
243 bh 6 return Shape(points)
244    
245 bh 143 def ShapesInRegion(self, box):
246     """Return the ids of the shapes that overlap the box.
247    
248     Box is a tuple (left, bottom, right, top) in the coordinate
249     system used by the layer's shapefile.
250     """
251     left, bottom, right, top = box
252 bh 147 return self.shapetree.find_shapes((left, bottom), (right, top))
253 bh 143
254 jonathan 725 def GetProjection(self):
255     return self.projection
256    
257 bh 6 def SetProjection(self, projection):
258     """Set the layer's projection"""
259     self.projection = projection
260     self.changed(LAYER_PROJECTION_CHANGED, self)
261    
262 jonathan 412 def GetClassification(self):
263     return self.__classification
264    
265     def SetClassification(self, clazz):
266 jonathan 492 """Set the classification to 'clazz'
267 jonathan 481
268 jonathan 492 If 'clazz' is None a default classification is created
269     """
270 jonathan 481
271 jonathan 529 # prevent infinite recursion when calling SetLayer()
272     if self.__setClassLock: return
273    
274     self.__setClassLock = True
275    
276 jonathan 492 if clazz is None:
277 jonathan 529 if self.__classification is not None:
278     self.__classification.SetLayer(None)
279 jonathan 492 self.__classification = classification.Classification()
280     else:
281     self.__classification = clazz
282 jonathan 529 try:
283     self.__classification.SetLayer(self)
284     except ValueError:
285     self.__setClassLock = False
286     raise ValueError
287 jonathan 492
288 jonathan 545 self.changed(LAYER_CHANGED, self)
289 jonathan 412
290 jonathan 529 self.__setClassLock = False
291    
292 jonathan 492 def ClassChanged(self):
293     """Called from the classification object when it has changed."""
294 jonathan 558 self.changed(LAYER_CHANGED, self)
295 jonathan 492
296 bh 217 def TreeInfo(self):
297     items = []
298    
299     if self.Visible():
300 jan 374 items.append(_("Shown"))
301 bh 217 else:
302 jan 374 items.append(_("Hidden"))
303     items.append(_("Shapes: %d") % self.NumShapes())
304 bh 217
305     bbox = self.LatLongBoundingBox()
306     if bbox is not None:
307 jan 374 items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
308 bh 217 else:
309 jan 374 items.append(_("Extent (lat-lon):"))
310     items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
311 bh 217
312 jonathan 736 if self.projection and len(self.projection.params) > 0:
313     items.append((_("Projection"),
314     [str(param) for param in self.projection.params]))
315    
316 jonathan 412 items.append(self.__classification)
317 bh 217
318 jan 374 return (_("Layer '%s'") % self.Title(), items)
319 jonathan 382
320 jonathan 736

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26