/[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 364 - (hide annotations)
Mon Jan 27 11:47:12 2003 UTC (22 years, 1 month ago) by jonathan
File MIME type: text/x-python
File size: 9201 byte(s)
added classification initializations

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