/[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 386 - (hide annotations)
Mon Feb 3 11:44:27 2003 UTC (22 years, 1 month ago) by jonathan
File MIME type: text/x-python
File size: 9681 byte(s)
Modified these functions to change the null data in the classification rather
than keep these values directly in the Layer class. Menu options to change
these values work again.

1 bh 73 # Copyright (c) 2001, 2002 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     __version__ = "$Revision$"
9    
10 bh 276 import os
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     from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
18     LAYER_VISIBILITY_CHANGED
19    
20     from color import Color
21     # Some predefined colors for internal use
22     _black = Color(0, 0, 0)
23    
24 jonathan 364 from classification import Classification
25 bh 6
26     from table import Table
27    
28     from base import TitledObject, Modifiable
29    
30     class Shape:
31    
32     """Represent one shape"""
33    
34     def __init__(self, points):
35     self.points = points
36     #self.compute_bbox()
37    
38     def compute_bbox(self):
39     xs = []
40     ys = []
41     for x, y in self.points:
42     xs.append(x)
43     ys.append(y)
44     self.llx = min(xs)
45     self.lly = min(ys)
46     self.urx = max(xs)
47     self.ury = max(ys)
48    
49     def Points(self):
50     return self.points
51    
52    
53    
54     # Shape type constants
55     SHAPETYPE_POLYGON = "polygon"
56     SHAPETYPE_ARC = "arc"
57     SHAPETYPE_POINT = "point"
58    
59     # mapping from shapelib shapetype constants to our constants
60     shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,
61     shapelib.SHPT_ARC: SHAPETYPE_ARC,
62     shapelib.SHPT_POINT: SHAPETYPE_POINT}
63    
64     shapetype_names = {SHAPETYPE_POINT: "Point",
65     SHAPETYPE_ARC: "Arc",
66     SHAPETYPE_POLYGON: "Polygon"}
67    
68     class BaseLayer(TitledObject, Modifiable):
69    
70     """Base class for the layers."""
71    
72     def __init__(self, title, visible = 1):
73     """Initialize the layer.
74    
75     title -- the title
76     visible -- boolean. If true the layer is visible.
77     """
78     TitledObject.__init__(self, title)
79     Modifiable.__init__(self)
80     self.visible = visible
81    
82     def Visible(self):
83     """Return true if layer is visible"""
84     return self.visible
85    
86     def SetVisible(self, visible):
87     """Set the layer's visibility."""
88     self.visible = visible
89     self.issue(LAYER_VISIBILITY_CHANGED, self)
90 bh 276
91    
92 bh 6 class Layer(BaseLayer):
93    
94     """Represent the information of one geodata file (currently a shapefile)
95    
96     All children of the layer have the same type.
97    
98     A layer has fill and stroke colors. Colors should be instances of
99     Color. They can also be None, indicating no fill or no stroke.
100    
101     The layer objects send the following events, all of which have the
102     layer object as parameter:
103    
104     TITLE_CHANGED -- The title has changed.
105     LAYER_PROJECTION_CHANGED -- the projection has changed.
106     LAYER_LEGEND_CHANGED -- the fill or stroke attributes have changed
107    
108     """
109    
110     def __init__(self, title, filename, projection = None,
111 bh 73 fill = None, stroke = _black, stroke_width = 1, visible = 1):
112 bh 6 """Initialize the layer.
113    
114     title -- the title
115     filename -- the name of the shapefile
116     projection -- the projection object. Its Inverse method is
117     assumed to map the layer's coordinates to lat/long
118     coordinates
119     fill -- the fill color or None if the shapes are not filled
120     stroke -- the stroke color or None if the shapes are not stroked
121     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     # Make the filename absolute. The filename will be
128     # interpreted relative to that anyway, but when saving a
129     # session we need to compare absolute paths and it's usually
130     # safer to always work with absolute paths.
131     self.filename = os.path.abspath(filename)
132    
133 bh 6 self.projection = projection
134     self.fill = fill
135     self.stroke = stroke
136 bh 73 self.stroke_width = stroke_width
137 bh 6 self.shapefile = None
138 bh 143 self.shapetree = None
139 bh 21 self.open_shapefile()
140 bh 6 # shapetable is the table associated with the shapefile, while
141     # table is the default table used to look up attributes for
142     # display
143     self.shapetable = Table(filename)
144     self.table = self.shapetable
145    
146 jonathan 364 self.classification = Classification()
147     self.classification.setNull(
148     {'stroke':stroke, 'stroke_width':stroke_width, 'fill':fill})
149    
150 bh 6 def open_shapefile(self):
151     if self.shapefile is None:
152     self.shapefile = shapelib.ShapeFile(self.filename)
153     numshapes, shapetype, mins, maxs = self.shapefile.info()
154     self.numshapes = numshapes
155     self.shapetype = shapelib_shapetypes[shapetype]
156    
157 bh 179 # if there are shapes, set the bbox accordinly. Otherwise
158     # set it to None.
159     if self.numshapes:
160     self.bbox = mins[:2] + maxs[:2]
161     else:
162     self.bbox = None
163    
164 bh 171 # estimate a good depth for the quad tree. Each depth
165     # multiplies the number of nodes by four, therefore we
166     # basically take the base 4 logarithm of the number of
167     # shapes.
168     if self.numshapes < 4:
169     maxdepth = 1
170     else:
171     maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
172    
173     self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
174     maxdepth)
175    
176 bh 258 def Destroy(self):
177 bh 260 BaseLayer.Destroy(self)
178 bh 258 if self.shapefile is not None:
179     self.shapefile.close()
180     self.shapefile = None
181     self.shapetree = None
182     self.table.Destroy()
183    
184 bh 6 def BoundingBox(self):
185 bh 179 """Return the layer's bounding box in the intrinsic coordinate system.
186    
187     If the layer has no shapes, return None.
188     """
189     # The bbox will be set by open_shapefile just as we need it
190     # here.
191 bh 6 self.open_shapefile()
192     return self.bbox
193    
194     def LatLongBoundingBox(self):
195 bh 179 """Return the layer's bounding box in lat/long coordinates.
196 bh 6
197 bh 179 Return None, if the layer doesn't contain any shapes.
198     """
199     bbox = self.BoundingBox()
200     if bbox is not None:
201     llx, lly, urx, ury = bbox
202     if self.projection is not None:
203     llx, lly = self.projection.Inverse(llx, lly)
204     urx, ury = self.projection.Inverse(urx, ury)
205     return llx, lly, urx, ury
206     else:
207     return None
208    
209 bh 6 def NumShapes(self):
210     """Return the number of shapes in the layer"""
211     self.open_shapefile()
212     return self.numshapes
213    
214     def ShapeType(self):
215     """Return the type of the shapes in the layer.
216     This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
217     """
218     self.open_shapefile()
219     return self.shapetype
220    
221     def Shape(self, index):
222     """Return the shape with index index"""
223     self.open_shapefile()
224     shape = self.shapefile.read_object(index)
225 jonathan 364
226 bh 6 if self.shapetype == SHAPETYPE_POINT:
227     points = shape.vertices()
228     else:
229     #for poly in shape.vertices():
230     poly = shape.vertices()[0]
231     points = []
232     for x, y in poly:
233 bh 82 points.append((x, y))
234 jonathan 364
235 bh 6 return Shape(points)
236    
237 bh 143 def ShapesInRegion(self, box):
238     """Return the ids of the shapes that overlap the box.
239    
240     Box is a tuple (left, bottom, right, top) in the coordinate
241     system used by the layer's shapefile.
242     """
243     left, bottom, right, top = box
244 bh 147 return self.shapetree.find_shapes((left, bottom), (right, top))
245 bh 143
246 bh 6 def SetProjection(self, projection):
247     """Set the layer's projection"""
248     self.projection = projection
249     self.changed(LAYER_PROJECTION_CHANGED, self)
250    
251     def SetFill(self, fill):
252     """Set the layer's fill color. None means the shapes are not filled"""
253 jonathan 386 null = self.classification.getNull()
254     null['fill'] = fill
255     self.classification.setNull(null)
256 bh 6 self.changed(LAYER_LEGEND_CHANGED, self)
257    
258     def SetStroke(self, stroke):
259     """Set the layer's stroke color. None means the shapes are not
260     stroked."""
261 jonathan 386 null = self.classification.getNull()
262     null['stroke'] = stroke
263     self.classification.setNull(null)
264 bh 6 self.changed(LAYER_LEGEND_CHANGED, self)
265 bh 73
266     def SetStrokeWidth(self, width):
267     """Set the layer's stroke width."""
268 jonathan 386 null = self.classification.getNull()
269     null['stroke_width'] = width
270     self.classification.setNull(null)
271 bh 73 self.changed(LAYER_LEGEND_CHANGED, self)
272 bh 217
273     def TreeInfo(self):
274     items = []
275    
276     if self.Visible():
277 jan 374 items.append(_("Shown"))
278 bh 217 else:
279 jan 374 items.append(_("Hidden"))
280     items.append(_("Shapes: %d") % self.NumShapes())
281 bh 217
282     bbox = self.LatLongBoundingBox()
283     if bbox is not None:
284 jan 374 items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
285 bh 217 else:
286 jan 374 items.append(_("Extent (lat-lon):"))
287     items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
288 bh 217
289     def color_string(color):
290     if color is None:
291     return "None"
292     return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)
293    
294 jonathan 382 # layers will always have a classification with at least a NULL data set
295    
296     #items.append((_("Fill: %s") % color_string(self.fill), self.fill))
297     #items.append((_("Outline: %s") % color_string(self.stroke), self.stroke))
298    
299     items.append(self.classification)
300    
301 jan 374 return (_("Layer '%s'") % self.Title(), items)
302 jonathan 382

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26