/[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 389 - (hide annotations)
Mon Feb 10 15:25:30 2003 UTC (22 years ago) by jonathan
File MIME type: text/x-python
File size: 8950 byte(s)
* Thuban/Model/layer.py (Layer): Remove the
        Set[Fill|Stroke|StrokeWidth]() methods. Code should call the
        SetDefault*() methods on the layer's classification object.
        (Layer.__init__): Use the new SetDefault*() methods in the
        Classification class.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26