/[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 437 - (show annotations)
Thu Feb 27 15:53:21 2003 UTC (22 years ago) by jonathan
File MIME type: text/x-python
File size: 8685 byte(s)
Fixed name resolution problem.

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 stroke_width = 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 None if the shapes are not filled
122 stroke -- the stroke color or 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.SetDefaultStroke(stroke)
147 self.__classification.SetDefaultStrokeWidth(stroke_width)
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 NumShapes(self):
212 """Return the number of shapes in the layer"""
213 self.open_shapefile()
214 return self.numshapes
215
216 def ShapeType(self):
217 """Return the type of the shapes in the layer.
218 This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
219 """
220 self.open_shapefile()
221 return self.shapetype
222
223 def Shape(self, index):
224 """Return the shape with index index"""
225 self.open_shapefile()
226 shape = self.shapefile.read_object(index)
227
228 if self.shapetype == SHAPETYPE_POINT:
229 points = shape.vertices()
230 else:
231 #for poly in shape.vertices():
232 poly = shape.vertices()[0]
233 points = []
234 for x, y in poly:
235 points.append((x, y))
236
237 return Shape(points)
238
239 def ShapesInRegion(self, box):
240 """Return the ids of the shapes that overlap the box.
241
242 Box is a tuple (left, bottom, right, top) in the coordinate
243 system used by the layer's shapefile.
244 """
245 left, bottom, right, top = box
246 return self.shapetree.find_shapes((left, bottom), (right, top))
247
248 def SetProjection(self, projection):
249 """Set the layer's projection"""
250 self.projection = projection
251 self.changed(LAYER_PROJECTION_CHANGED, self)
252
253 def GetClassification(self):
254 return self.__classification
255
256 def SetClassification(self, clazz):
257 self.__classification = clazz
258 self.changed(LAYER_LEGEND_CHANGED, self)
259
260 def TreeInfo(self):
261 items = []
262
263 if self.Visible():
264 items.append(_("Shown"))
265 else:
266 items.append(_("Hidden"))
267 items.append(_("Shapes: %d") % self.NumShapes())
268
269 bbox = self.LatLongBoundingBox()
270 if bbox is not None:
271 items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
272 else:
273 items.append(_("Extent (lat-lon):"))
274 items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
275
276 items.append(self.__classification)
277
278 return (_("Layer '%s'") % self.Title(), items)
279

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26