/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 607 - (show annotations)
Fri Apr 4 12:16:57 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 13745 byte(s)
(ClassGenDialog): Dialog for generating
        classifications.
(GenRangePanel): Panel specific to range generation.
(GenSingletonPanel): Panel specific to singleton generation.
(ClassGenerator): Class responsible for actually generating
        the classification from the data gathered in the dialog box.
(PropertyRamp): Generates properties whose values range from
        a starting property to an ending property.

1 # Copyright (c) 2003 by Intevation GmbH
2 # Authors:
3 # Jonathan Coles <[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 from Thuban import _
9
10 from wxPython.wx import *
11
12 from Thuban.Model.classification import Classification, ClassGroupRange, \
13 ClassGroupSingleton, ClassGroupProperties
14
15 from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
16 FIELDTYPE_STRING
17
18 from Thuban.Model.color import Color
19
20 ID_CLASSGEN_GEN = 4001
21 ID_CLASSGEN_CANCEL = 4002
22
23 class ClassGenDialog(wxDialog):
24
25 def __init__(self, parent, table, fieldName):
26 wxDialog.__init__(self, parent, -1, _("Generate Classification"),
27 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
28
29 self.clazz = None
30
31 type, name, width, prec = table.field_info_by_name(fieldName)
32
33 sizer = wxBoxSizer(wxVERTICAL)
34
35 buttonSizer = wxBoxSizer(wxHORIZONTAL)
36 self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))
37 buttonSizer.Add(self.genButton, 0, wxALL, 4)
38 buttonSizer.Add(60, 20, 0, wxALL, 4)
39 buttonSizer.Add(wxButton(self, ID_CLASSGEN_CANCEL, _("Cancel")),
40 0, wxALL, 4)
41
42 if type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
43 self.panel = GenRangePanel(self, table, fieldName, type)
44 elif type == FIELDTYPE_STRING:
45 print "Select a field that is an int/decimal"
46 #panel = GenSingletonPanel(self, table, fieldName)
47 else:
48 assert False, "Shouldn't be here."
49 pass
50
51 sizer.Add(self.panel, 1, wxGROW | wxALL, 4)
52 sizer.Add(buttonSizer, 0,
53 wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)
54
55 self.SetSizer(sizer)
56 self.SetAutoLayout(True)
57 sizer.SetSizeHints(self)
58
59 EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)
60 EVT_BUTTON(self, ID_CLASSGEN_CANCEL, self._OnCancel)
61
62 def GetClassification(self):
63 return self.clazz
64
65 def AllowGenerate(self, on):
66 self.genButton.Enable(on)
67
68 def _OnGenerate(self, event):
69 min = self.panel.GetMin()
70 max = self.panel.GetMax()
71 numGroups = self.panel.GetNumGroups()
72 cgp = ClassGroupProperties()
73 cgp2 = ClassGroupProperties()
74
75 cgp.SetLineColor(Color(.5, 0, 0))
76 cgp2.SetLineColor(Color(1, 0, 1))
77 cgp2.SetLineWidth(10)
78
79 if min is not None \
80 and max is not None \
81 and numGroups is not None:
82 self.clazz = ClassGenerator().GenerateRanges(min, max,
83 numGroups, cgp, cgp2)
84 else:
85 self.clazz = None # for now
86
87 self.EndModal(wxID_OK)
88
89 def _OnCancel(self, event):
90 self.EndModal(wxID_CANCEL)
91
92 ID_RANGE_MIN = 4001
93 ID_RANGE_MAX = 4002
94 ID_RANGE_NGROUPS = 4003
95 ID_RANGE_STEP = 4004
96
97 class GenRangePanel(wxPanel):
98
99 def __init__(self, parent, table, fieldName, fieldType):
100 wxPanel.__init__(self, parent, -1)
101
102 self.parent = parent
103
104 self.fieldType = fieldType
105
106 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, "Ranges"),
107 wxVERTICAL)
108
109 sizer = wxBoxSizer(wxHORIZONTAL)
110
111 sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
112 self.minCtrl = wxTextCtrl(self, ID_RANGE_MIN, style=wxTE_RIGHT)
113 sizer.Add(self.minCtrl, 0, wxALL, 4)
114 EVT_TEXT(self, ID_RANGE_MIN, self._OnRangeChanged)
115 self.goodTextColour = self.minCtrl.GetForegroundColour()
116 self.badTextColour = wxRED
117
118 sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
119 self.maxCtrl = wxTextCtrl(self, ID_RANGE_MAX, style=wxTE_RIGHT)
120 sizer.Add(self.maxCtrl, 0, wxALL, 4)
121 EVT_TEXT(self, ID_RANGE_MAX, self._OnRangeChanged)
122 topSizer.Add(sizer, 0, wxALL, 4)
123
124 sizer = wxBoxSizer(wxHORIZONTAL)
125 sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
126 self.numGroupsCtrl = wxSpinCtrl(self, ID_RANGE_NGROUPS, style=wxTE_RIGHT)
127 EVT_TEXT(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)
128 EVT_SPINCTRL(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)
129 sizer.Add(self.numGroupsCtrl, 0, wxALL, 4)
130
131 sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
132 self.stepCtrl = wxTextCtrl(self, ID_RANGE_STEP, style=wxTE_RIGHT)
133 EVT_TEXT(self, ID_RANGE_STEP, self._OnSteppingChanged)
134 sizer.Add(self.stepCtrl , 0, wxALL, 4)
135 topSizer.Add(sizer, 0, wxALL, 4)
136
137 self.SetSizer(topSizer)
138 self.SetAutoLayout(True)
139 topSizer.SetSizeHints(self)
140
141 self.numGroupsChanging = False
142 self.steppingChanging = False
143
144 self.numGroupsCtrl.SetRange(1, 100)
145
146 self.numGroupsCtrl.SetValue(1)
147 self.stepCtrl.SetValue("1")
148 self.maxCtrl.SetValue("0")
149 self.minCtrl.SetValue("0")
150 self.minCtrl.SetFocus()
151
152 def GetNumGroups(self):
153 value = self.numGroupsCtrl.GetValue()
154 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
155 value,
156 FIELDTYPE_INT,
157 None)
158
159 ##if self.__ValidateEntry(self.numGroupsCtrl, value, int):
160 #return value
161
162 #return None
163
164 def GetStepping(self):
165 step = self.stepCtrl.GetValue()
166 return self.__GetValidatedTypeEntry(self.stepCtrl,
167 step,
168 self.fieldType,
169 0)
170
171 def GetMin(self):
172 min = self.minCtrl.GetValue()
173 max = self.maxCtrl.GetValue()
174 return self.__GetValidatedTypeEntry(self.minCtrl,
175 min,
176 self.fieldType,
177 max)
178
179 def GetMax(self):
180 min = self.minCtrl.GetValue()
181 max = self.maxCtrl.GetValue()
182 return self.__GetValidatedTypeEntry(self.maxCtrl,
183 max,
184 self.fieldType,
185 min)
186
187 def _OnRangeChanged(self, event):
188
189 hasFocus = wxWindow_FindFocus() == event.GetEventObject()
190 min = self.GetMin()
191 max = self.GetMax()
192
193 on = min is not None \
194 and max is not None
195
196 self.numGroupsCtrl.Enable(on)
197 self.stepCtrl.Enable(on)
198
199 if on:
200 self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)
201
202 ngroups = self.GetNumGroups()
203
204 if ngroups is not None \
205 and min is not None \
206 and max is not None \
207 and ngroups != 0:
208
209 self.stepCtrl.SetValue(str((max - min) / ngroups))
210
211 self.parent.AllowGenerate(self.GetStepping() is not None)
212 else:
213 self.parent.AllowGenerate(False)
214
215
216 if hasFocus:
217 event.GetEventObject().SetFocus()
218
219 def _OnNumGroupsChanged(self, event):
220 if self.steppingChanging:
221 self.steppingChanging = False
222 return
223
224
225 obj = event.GetEventObject()
226 ngroups = self.GetNumGroups()
227 min = self.GetMin()
228 max = self.GetMax()
229
230 if ngroups >= self.numGroupsCtrl.GetMax():
231 self.numGroupsCtrl.SetRange(1, ngroups + 1)
232
233 if ngroups is not None \
234 and min is not None \
235 and max is not None \
236 and ngroups != 0:
237
238 #
239 # changing the value in the stepCtrl sends an event
240 # that the control is changing, at which point
241 # we try to update the numGroupsCtrl. This causes
242 # an infinite recursion. This flag and the one
243 # called steppingChanging tries to prevent the recursion.
244 #
245 self.numGroupsChanging = True
246 self.stepCtrl.SetValue(str((max - min) / ngroups))
247
248 self.parent.AllowGenerate(self.GetStepping() is not None)
249 else:
250 self.parent.AllowGenerate(False)
251
252
253 def _OnSteppingChanged(self, event):
254 if self.numGroupsChanging:
255 self.numGroupsChanging = False
256 return
257
258 step = self.GetStepping()
259 min = self.GetMin()
260 max = self.GetMax()
261
262 if step is not None \
263 and min is not None \
264 and max is not None \
265 and step != 0:
266
267 #
268 # see note in _OnNumGroupsChanged
269 #
270 self.steppingChanging = True
271 n = int((max - min) / step)
272 if n == 0:
273 n = 1
274
275 self.numGroupsCtrl.SetValue(n)
276
277 self.parent.AllowGenerate(self.GetNumGroups() is not None)
278 else:
279 self.parent.AllowGenerate(False)
280
281 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
282
283 if type == FIELDTYPE_INT:
284 func = int
285 elif type == FIELDTYPE_DOUBLE:
286 func = float
287 elif type == FIELDTYPE_STRING:
288 func = str
289 else:
290 assert False, "Unsupported FIELDTYPE"
291 pass
292
293 if self.__ValidateEntry(win, value, func, badValue):
294 return func(value)
295
296 return None
297
298 def __ValidateEntry(self, win, value, test, badValue = None):
299
300 valid = value != ""
301
302 try:
303 if valid:
304 value = test(value)
305
306 if badValue is not None:
307 valid = value != test(badValue)
308 except ValueError:
309 valid = False
310
311 if valid:
312 win.SetForegroundColour(wxBLACK)
313 else:
314 win.SetForegroundColour(wxRED)
315
316 return valid
317
318
319 class GenSingletonPanel(wxPanel):
320
321 def __init__(self, parent, table, fieldName, fieldType):
322 wxPanel.__init__(self, parent, -1)
323
324
325 class ClassGenerator:
326
327 def GenerateSingletons(self, list, numGroups, prop1, prop2):
328 """Generate a new classification consisting solely of singletons.
329
330 The resulting classification will consist of at most 'numGroups'
331 groups whose group properties ramp between 'prop1' and 'prop2'. There
332 could be fewer groups if 'list' contains fewer that 'numGroups' items.
333
334 list -- any object that implements the iterator interface
335
336 numGroups -- how many groups to generate. This can not be
337 determined while the classification is being
338 generated because the stepping values must
339 be precalculated to ramp between prop1 and prop2.
340
341 prop1 -- initial group property values
342
343 prop2 -- final group property values
344 """
345
346 clazz = Classification()
347 if numGroups == 0: return clazz
348
349 for value, prop in zip(list, PropertyRamp(numGroups, prop1, prop2)):
350 clazz.AddGroup(ClassGroupSingleton(value, prop))
351
352 return clazz
353
354 def GenerateRanges(self, min, max, numGroups, prop1, prop2):
355
356 clazz = Classification()
357 if numGroups == 0: return clazz
358
359 step = (max - min) / float(numGroups)
360
361 cur_min = min
362 cur_max = cur_min + step
363
364 i = 0
365 for prop in PropertyRamp(numGroups, prop1, prop2):
366
367 if i == (numGroups - 1):
368 cur_max = max
369
370 # this check guards against rounding issues
371 if cur_min != cur_max:
372 clazz.AddGroup(ClassGroupRange(cur_min, cur_max, prop))
373
374 cur_min = cur_max
375 cur_max += step
376 i += 1
377
378 return clazz
379
380 class PropertyRamp:
381
382 def __init__(self, num, prop1, prop2):
383
384 self.count = int(num)
385 num = float(num)
386
387
388 self.lineColor = prop1.GetLineColor()
389 self.fillColor = prop1.GetFill()
390 self.lineWidth = prop1.GetLineWidth()
391
392 lineColor2 = prop2.GetLineColor()
393 fillColor2 = prop2.GetFill()
394 lineWidth2 = prop2.GetLineWidth()
395
396 self.line_redStep = (lineColor2.red - self.lineColor.red) / num
397 self.line_greenStep = (lineColor2.green - self.lineColor.green) / num
398 self.line_blueStep = (lineColor2.blue - self.lineColor.blue) / num
399
400 self.line_widthStep = (lineWidth2 - self.lineWidth) / num
401
402 self.fill_redStep = (fillColor2.red - self.fillColor.red) / num
403 self.fill_greenStep = (fillColor2.green - self.fillColor.green) / num
404 self.fill_blueStep = (fillColor2.blue - self.fillColor.blue) / num
405
406 def __iter__(self):
407 return self
408
409 def next(self):
410 if self.count == 0:
411 raise StopIteration
412
413 prop = ClassGroupProperties()
414 prop.SetFill(self.fillColor)
415 prop.SetLineColor(self.lineColor)
416 prop.SetLineWidth(int(self.lineWidth))
417
418 self.lineColor.red += self.line_redStep
419 self.lineColor.green += self.line_greenStep
420 self.lineColor.blue += self.line_blueStep
421
422 self.fillColor.red += self.fill_redStep
423 self.fillColor.green += self.fill_greenStep
424 self.fillColor.blue += self.fill_blueStep
425
426 self.lineWidth += self.line_widthStep
427
428 self.count -= 1
429
430 return prop
431

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26