/[thuban]/trunk/thuban/Thuban/Model/layer.py
ViewVC logotype

Annotation of /trunk/thuban/Thuban/Model/layer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 794 - (hide annotations)
Wed Apr 30 17:00:52 2003 UTC (21 years, 10 months ago) by jonathan
File MIME type: text/x-python
File size: 9773 byte(s)
(Layer.ShapesInRegion): Fix docstring
        to say that the parameter is a tuple of unprojected
        points (which is what the callers to this method were assuming).
        Also, since the points are unprojected we need to projected them.

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 jonathan 794 Box is a tuple (left, bottom, right, top) in unprojected coordinates.
249 bh 143 """
250     left, bottom, right, top = box
251 jonathan 794
252     if self.projection is not None:
253     left, bottom = self.projection.Forward(left, bottom)
254     right, top = self.projection.Forward(right, top)
255    
256 bh 147 return self.shapetree.find_shapes((left, bottom), (right, top))
257 bh 143
258 jonathan 725 def GetProjection(self):
259     return self.projection
260    
261 bh 6 def SetProjection(self, projection):
262     """Set the layer's projection"""
263     self.projection = projection
264     self.changed(LAYER_PROJECTION_CHANGED, self)
265    
266 jonathan 412 def GetClassification(self):
267     return self.__classification
268    
269     def SetClassification(self, clazz):
270 jonathan 492 """Set the classification to 'clazz'
271 jonathan 481
272 jonathan 492 If 'clazz' is None a default classification is created
273     """
274 jonathan 481
275 jonathan 529 # prevent infinite recursion when calling SetLayer()
276     if self.__setClassLock: return
277    
278     self.__setClassLock = True
279    
280 jonathan 492 if clazz is None:
281 jonathan 529 if self.__classification is not None:
282     self.__classification.SetLayer(None)
283 jonathan 492 self.__classification = classification.Classification()
284     else:
285     self.__classification = clazz
286 jonathan 529 try:
287     self.__classification.SetLayer(self)
288     except ValueError:
289     self.__setClassLock = False
290     raise ValueError
291 jonathan 492
292 jonathan 545 self.changed(LAYER_CHANGED, self)
293 jonathan 412
294 jonathan 529 self.__setClassLock = False
295    
296 jonathan 492 def ClassChanged(self):
297     """Called from the classification object when it has changed."""
298 jonathan 558 self.changed(LAYER_CHANGED, self)
299 jonathan 492
300 bh 217 def TreeInfo(self):
301     items = []
302    
303     if self.Visible():
304 jan 374 items.append(_("Shown"))
305 bh 217 else:
306 jan 374 items.append(_("Hidden"))
307     items.append(_("Shapes: %d") % self.NumShapes())
308 bh 217
309     bbox = self.LatLongBoundingBox()
310     if bbox is not None:
311 jan 374 items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
312 bh 217 else:
313 jan 374 items.append(_("Extent (lat-lon):"))
314     items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
315 bh 217
316 jonathan 736 if self.projection and len(self.projection.params) > 0:
317     items.append((_("Projection"),
318     [str(param) for param in self.projection.params]))
319    
320 jonathan 412 items.append(self.__classification)
321 bh 217
322 jan 374 return (_("Layer '%s'") % self.Title(), items)
323 jonathan 382
324 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