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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 464 - (show annotations)
Wed Mar 5 18:17:47 2003 UTC (22 years ago) by jonathan
File MIME type: text/x-python
File size: 8912 byte(s)
(Layer): Add GetFieldType to retreive the kind of data represented by a field.

1 # Copyright (c) 2001, 2002 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 # Jonathan Coles <[email protected]>
5 #
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 import os
12 from math import log, ceil
13
14 from Thuban import _
15
16 import shapelib, shptree
17
18 from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
19 LAYER_VISIBILITY_CHANGED
20
21 from color import Color
22
23 import classification
24
25 from table import Table
26
27 from base import TitledObject, Modifiable
28
29 class Shape:
30
31 """Represent one shape"""
32
33 def __init__(self, points):
34 self.points = points
35 #self.compute_bbox()
36
37 def compute_bbox(self):
38 xs = []
39 ys = []
40 for x, y in self.points:
41 xs.append(x)
42 ys.append(y)
43 self.llx = min(xs)
44 self.lly = min(ys)
45 self.urx = max(xs)
46 self.ury = max(ys)
47
48 def Points(self):
49 return self.points
50
51
52
53 # Shape type constants
54 SHAPETYPE_POLYGON = "polygon"
55 SHAPETYPE_ARC = "arc"
56 SHAPETYPE_POINT = "point"
57
58 # mapping from shapelib shapetype constants to our constants
59 shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,
60 shapelib.SHPT_ARC: SHAPETYPE_ARC,
61 shapelib.SHPT_POINT: SHAPETYPE_POINT}
62
63 shapetype_names = {SHAPETYPE_POINT: "Point",
64 SHAPETYPE_ARC: "Arc",
65 SHAPETYPE_POLYGON: "Polygon"}
66
67 class BaseLayer(TitledObject, Modifiable):
68
69 """Base class for the layers."""
70
71 def __init__(self, title, visible = 1):
72 """Initialize the layer.
73
74 title -- the title
75 visible -- boolean. If true the layer is visible.
76 """
77 TitledObject.__init__(self, title)
78 Modifiable.__init__(self)
79 self.visible = visible
80
81 def Visible(self):
82 """Return true if layer is visible"""
83 return self.visible
84
85 def SetVisible(self, visible):
86 """Set the layer's visibility."""
87 self.visible = visible
88 self.issue(LAYER_VISIBILITY_CHANGED, self)
89
90
91 class Layer(BaseLayer):
92
93 """Represent the information of one geodata file (currently a shapefile)
94
95 All children of the layer have the same type.
96
97 A layer has fill and stroke colors. Colors should be instances of
98 Color. They can also be None, indicating no fill or no stroke.
99
100 The layer objects send the following events, all of which have the
101 layer object as parameter:
102
103 TITLE_CHANGED -- The title has changed.
104 LAYER_PROJECTION_CHANGED -- the projection has changed.
105 LAYER_LEGEND_CHANGED -- the fill or stroke attributes have changed
106
107 """
108
109 def __init__(self, title, filename, projection = None,
110 fill = Color.None,
111 stroke = Color.Black,
112 lineWidth = 1,
113 visible = 1):
114 """Initialize the layer.
115
116 title -- the title
117 filename -- the name of the shapefile
118 projection -- the projection object. Its Inverse method is
119 assumed to map the layer's coordinates to lat/long
120 coordinates
121 fill -- the fill color or Color.None if the shapes are not filled
122 stroke -- the stroke color or Color.None if the shapes are not stroked
123 visible -- boolean. If true the layer is visible.
124
125 colors are expected to be instances of Color class
126 """
127 BaseLayer.__init__(self, title, visible = visible)
128
129 # Make the filename absolute. The filename will be
130 # interpreted relative to that anyway, but when saving a
131 # session we need to compare absolute paths and it's usually
132 # safer to always work with absolute paths.
133 self.filename = os.path.abspath(filename)
134
135 self.projection = projection
136 self.shapefile = None
137 self.shapetree = None
138 self.open_shapefile()
139 # shapetable is the table associated with the shapefile, while
140 # table is the default table used to look up attributes for
141 # display
142 self.shapetable = Table(filename)
143 self.table = self.shapetable
144
145 self.__classification = classification.Classification(self)
146 self.__classification.SetDefaultLineColor(stroke)
147 self.__classification.SetDefaultLineWidth(lineWidth)
148 self.__classification.SetDefaultFill(fill)
149
150 self.UnsetModified()
151
152 def open_shapefile(self):
153 if self.shapefile is None:
154 self.shapefile = shapelib.ShapeFile(self.filename)
155 numshapes, shapetype, mins, maxs = self.shapefile.info()
156 self.numshapes = numshapes
157 self.shapetype = shapelib_shapetypes[shapetype]
158
159 # if there are shapes, set the bbox accordinly. Otherwise
160 # set it to None.
161 if self.numshapes:
162 self.bbox = mins[:2] + maxs[:2]
163 else:
164 self.bbox = None
165
166 # 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
178 def Destroy(self):
179 BaseLayer.Destroy(self)
180 if self.shapefile is not None:
181 self.shapefile.close()
182 self.shapefile = None
183 self.shapetree = None
184 self.table.Destroy()
185
186 def BoundingBox(self):
187 """Return the layer's bounding box in the intrinsic coordinate system.
188
189 If the layer has no shapes, return None.
190 """
191 # The bbox will be set by open_shapefile just as we need it
192 # here.
193 self.open_shapefile()
194 return self.bbox
195
196 def LatLongBoundingBox(self):
197 """Return the layer's bounding box in lat/long coordinates.
198
199 Return None, if the layer doesn't contain any shapes.
200 """
201 bbox = self.BoundingBox()
202 if bbox is not None:
203 llx, lly, urx, ury = bbox
204 if self.projection is not None:
205 llx, lly = self.projection.Inverse(llx, lly)
206 urx, ury = self.projection.Inverse(urx, ury)
207 return llx, lly, urx, ury
208 else:
209 return None
210
211 def GetFieldType(self, fieldName):
212 self.open_shapefile()
213 info = self.table.field_info_by_name(fieldName)
214 if info is not None:
215 return info[0]
216 else:
217 return None
218
219 def NumShapes(self):
220 """Return the number of shapes in the layer"""
221 self.open_shapefile()
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 self.open_shapefile()
229 return self.shapetype
230
231 def Shape(self, index):
232 """Return the shape with index index"""
233 self.open_shapefile()
234 shape = self.shapefile.read_object(index)
235
236 if self.shapetype == SHAPETYPE_POINT:
237 points = shape.vertices()
238 else:
239 #for poly in shape.vertices():
240 poly = shape.vertices()[0]
241 points = []
242 for x, y in poly:
243 points.append((x, y))
244
245 return Shape(points)
246
247 def ShapesInRegion(self, box):
248 """Return the ids of the shapes that overlap the box.
249
250 Box is a tuple (left, bottom, right, top) in the coordinate
251 system used by the layer's shapefile.
252 """
253 left, bottom, right, top = box
254 return self.shapetree.find_shapes((left, bottom), (right, top))
255
256 def SetProjection(self, projection):
257 """Set the layer's projection"""
258 self.projection = projection
259 self.changed(LAYER_PROJECTION_CHANGED, self)
260
261 def GetClassification(self):
262 return self.__classification
263
264 def SetClassification(self, clazz):
265 self.__classification = clazz
266 self.changed(LAYER_LEGEND_CHANGED, self)
267
268 def TreeInfo(self):
269 items = []
270
271 if self.Visible():
272 items.append(_("Shown"))
273 else:
274 items.append(_("Hidden"))
275 items.append(_("Shapes: %d") % self.NumShapes())
276
277 bbox = self.LatLongBoundingBox()
278 if bbox is not None:
279 items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
280 else:
281 items.append(_("Extent (lat-lon):"))
282 items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
283
284 items.append(self.__classification)
285
286 return (_("Layer '%s'") % self.Title(), items)
287

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26