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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 607 - (hide 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 jonathan 607 # 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