/[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 276 - (hide annotations)
Fri Aug 23 15:25:07 2002 UTC (22 years, 6 months ago) by bh
File MIME type: text/x-python
File size: 8999 byte(s)
(Layer.__init__): Make sure we have an
absolute filename.

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 bh 143 import shapelib, shptree
14 bh 6
15     from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
16     LAYER_VISIBILITY_CHANGED
17    
18     from color import Color
19     # Some predefined colors for internal use
20     _black = Color(0, 0, 0)
21    
22    
23     from table import Table
24    
25     from base import TitledObject, Modifiable
26    
27     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     def __init__(self, title, visible = 1):
70     """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     LAYER_LEGEND_CHANGED -- the fill or stroke attributes have changed
104    
105     """
106    
107     def __init__(self, title, filename, projection = None,
108 bh 73 fill = None, stroke = _black, stroke_width = 1, visible = 1):
109 bh 6 """Initialize the layer.
110    
111     title -- the title
112     filename -- the name of the shapefile
113     projection -- the projection object. Its Inverse method is
114     assumed to map the layer's coordinates to lat/long
115     coordinates
116     fill -- the fill color or None if the shapes are not filled
117     stroke -- the stroke color or None if the shapes are not stroked
118     visible -- boolean. If true the layer is visible.
119    
120     colors are expected to be instances of Color class
121     """
122     BaseLayer.__init__(self, title, visible = visible)
123 bh 276
124     # Make the filename absolute. The filename will be
125     # interpreted relative to that anyway, but when saving a
126     # session we need to compare absolute paths and it's usually
127     # safer to always work with absolute paths.
128     self.filename = os.path.abspath(filename)
129    
130 bh 6 self.projection = projection
131     self.fill = fill
132     self.stroke = stroke
133 bh 73 self.stroke_width = stroke_width
134 bh 6 self.shapefile = None
135 bh 143 self.shapetree = None
136 bh 21 self.open_shapefile()
137 bh 6 # shapetable is the table associated with the shapefile, while
138     # table is the default table used to look up attributes for
139     # display
140     self.shapetable = Table(filename)
141     self.table = self.shapetable
142    
143     def open_shapefile(self):
144     if self.shapefile is None:
145     self.shapefile = shapelib.ShapeFile(self.filename)
146     numshapes, shapetype, mins, maxs = self.shapefile.info()
147     self.numshapes = numshapes
148     self.shapetype = shapelib_shapetypes[shapetype]
149    
150 bh 179 # if there are shapes, set the bbox accordinly. Otherwise
151     # set it to None.
152     if self.numshapes:
153     self.bbox = mins[:2] + maxs[:2]
154     else:
155     self.bbox = None
156    
157 bh 171 # estimate a good depth for the quad tree. Each depth
158     # multiplies the number of nodes by four, therefore we
159     # basically take the base 4 logarithm of the number of
160     # shapes.
161     if self.numshapes < 4:
162     maxdepth = 1
163     else:
164     maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
165    
166     self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
167     maxdepth)
168    
169 bh 258 def Destroy(self):
170 bh 260 BaseLayer.Destroy(self)
171 bh 258 if self.shapefile is not None:
172     self.shapefile.close()
173     self.shapefile = None
174     self.shapetree = None
175     self.table.Destroy()
176    
177 bh 6 def BoundingBox(self):
178 bh 179 """Return the layer's bounding box in the intrinsic coordinate system.
179    
180     If the layer has no shapes, return None.
181     """
182     # The bbox will be set by open_shapefile just as we need it
183     # here.
184 bh 6 self.open_shapefile()
185     return self.bbox
186    
187     def LatLongBoundingBox(self):
188 bh 179 """Return the layer's bounding box in lat/long coordinates.
189 bh 6
190 bh 179 Return None, if the layer doesn't contain any shapes.
191     """
192     bbox = self.BoundingBox()
193     if bbox is not None:
194     llx, lly, urx, ury = bbox
195     if self.projection is not None:
196     llx, lly = self.projection.Inverse(llx, lly)
197     urx, ury = self.projection.Inverse(urx, ury)
198     return llx, lly, urx, ury
199     else:
200     return None
201    
202 bh 6 def NumShapes(self):
203     """Return the number of shapes in the layer"""
204     self.open_shapefile()
205     return self.numshapes
206    
207     def ShapeType(self):
208     """Return the type of the shapes in the layer.
209     This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
210     """
211     self.open_shapefile()
212     return self.shapetype
213    
214     def Shape(self, index):
215     """Return the shape with index index"""
216     self.open_shapefile()
217     shape = self.shapefile.read_object(index)
218     if self.shapetype == SHAPETYPE_POINT:
219     points = shape.vertices()
220     else:
221     #for poly in shape.vertices():
222     poly = shape.vertices()[0]
223     points = []
224     for x, y in poly:
225 bh 82 points.append((x, y))
226 bh 6 return Shape(points)
227    
228 bh 143 def ShapesInRegion(self, box):
229     """Return the ids of the shapes that overlap the box.
230    
231     Box is a tuple (left, bottom, right, top) in the coordinate
232     system used by the layer's shapefile.
233     """
234     left, bottom, right, top = box
235 bh 147 return self.shapetree.find_shapes((left, bottom), (right, top))
236 bh 143
237 bh 6 def SetProjection(self, projection):
238     """Set the layer's projection"""
239     self.projection = projection
240     self.changed(LAYER_PROJECTION_CHANGED, self)
241    
242     def SetFill(self, fill):
243     """Set the layer's fill color. None means the shapes are not filled"""
244     self.fill = fill
245     self.changed(LAYER_LEGEND_CHANGED, self)
246    
247     def SetStroke(self, stroke):
248     """Set the layer's stroke color. None means the shapes are not
249     stroked."""
250     self.stroke = stroke
251     self.changed(LAYER_LEGEND_CHANGED, self)
252 bh 73
253     def SetStrokeWidth(self, width):
254     """Set the layer's stroke width."""
255     self.stroke_width = width
256     self.changed(LAYER_LEGEND_CHANGED, self)
257 bh 217
258     def TreeInfo(self):
259     items = []
260    
261     if self.Visible():
262     items.append("Shown")
263     else:
264     items.append("Hidden")
265     items.append("Shapes: %d" % self.NumShapes())
266    
267     bbox = self.LatLongBoundingBox()
268     if bbox is not None:
269     items.append("Extent (lat-lon): (%g, %g, %g, %g)" % bbox)
270     else:
271     items.append("Extent (lat-lon):")
272     items.append("Shapetype: %s" % shapetype_names[self.ShapeType()])
273    
274     def color_string(color):
275     if color is None:
276     return "None"
277     return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)
278     items.append("Fill: " + color_string(self.fill))
279     items.append("Outline: " + color_string(self.stroke))
280    
281     return ("Layer '%s'" % self.Title(), items)

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26