/[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 258 - (hide annotations)
Thu Aug 15 12:48:03 2002 UTC (22 years, 6 months ago) by bh
File MIME type: text/x-python
File size: 8737 byte(s)
(Layer.Destroy): New. Explicitly close the
shapefile and destroy the table.

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