/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 410 by jonathan, Wed Feb 19 16:51:12 2003 UTC revision 453 by bh, Tue Mar 4 11:31:39 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  #  #
# Line 16  an input value falls with a range that d Line 16  an input value falls with a range that d
16  If no mapping can be found then default data will  If no mapping can be found then default data will
17  be returned. Input values must be hashable objects  be returned. Input values must be hashable objects
18    
19  See the description of getProperties() for more information  See the description of GetGroup() for more information
20  on the mapping algorithm.  on the mapping algorithm.
21  """  """
22        
23  # fix for people using python2.1  # fix for people using python2.1
24  from __future__ import nested_scopes  from __future__ import nested_scopes
25    
26    from types import *
27    
28  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
29       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED
30    
31  from Thuban import _  from Thuban import _
32  from Thuban.Model.color import Color  from Thuban.Model.color import Color
33    
34  from wxPython.wx import *  import Thuban.Model.layer
35    
36    
37  # constants  # constants
38  RANGE_MIN  = 0  RANGE_MIN  = 0
# Line 47  class Classification: Line 50  class Classification:
50                      is to be used to classify layer properties                      is to be used to classify layer properties
51          """          """
52    
53            self.layer = None # stop message sending
54    
55            self.SetDefaultGroup(ClassGroupDefault())
56            self.SetField(field)
57    
58          self.layer = layer          self.layer = layer
59          self.points = {}          self.points = []
60          self.ranges = []          self.ranges = []
61          self.maps   = []          self.maps   = []
         self.DefaultData = ClassDataDefault()  
         self.field = field  
         #self.SetField(field)  
62    
63      def SendMessage(self, message):      def __iter__(self):
64            return ClassIterator(self.DefaultGroup,
65                                 self.points,
66                                 self.ranges,
67                                 self.maps)
68    
69        def __SendMessage(self, message):
70          if self.layer is not None:          if self.layer is not None:
71              self.layer.changed(message, self.layer)              self.layer.changed(message, self.layer)
72            
# Line 65  class Classification: Line 76  class Classification:
76             field -- if None then all values map to the default data             field -- if None then all values map to the default data
77          """          """
78    
79            if field == "":
80                field = None
81    
82          self.field = field          self.field = field
83          self.SendMessage(LAYER_LEGEND_CHANGED)          self.__SendMessage(LAYER_LEGEND_CHANGED)
84    
85      def GetField(self):      def GetField(self):
86          return self.field          return self.field
87    
88      def SetLayer(self, layer):      def SetLayer(self, layer):
89            assert(isinstance(layer, Thuban.Model.layer.Layer))
90          self.layer = layer          self.layer = layer
91          self.SendMessage(LAYER_LEGEND_CHANGED)          self.__SendMessage(LAYER_LEGEND_CHANGED)
92    
93      def GetLayer(self):      def GetLayer(self):
94          return layer.self          return layer.self
95    
96      def SetDefaultData(self, data):      def SetDefaultGroup(self, group):
97          """Set the data to be used when a value can't be classified.          """Set the group to be used when a value can't be classified.
98    
99             data -- data that the value maps to. See class description.             group -- group that the value maps to. See class description.
100          """          """
101    
102          self.DefaultData = data          assert(isinstance(group, ClassGroupDefault))
103            self.DefaultGroup = group
104    
105        def GetDefaultGroup(self):
106            return self.DefaultGroup
107    
108      def GetDefaultData(self):      #
109          return self.DefaultData      # these SetDefault* methods are really only provided for
110        # some backward compatibility. they should be considered
111        # for removal once all the classification code is finished.
112        #
113    
114      def SetDefaultFill(self, fill):      def SetDefaultFill(self, fill):
115          self.DefaultData.SetFill(fill)          assert(isinstance(fill, Color))
116          self.SendMessage(LAYER_LEGEND_CHANGED)          self.DefaultGroup.GetProperties().SetFill(fill)
117            self.__SendMessage(LAYER_LEGEND_CHANGED)
118                    
119      def GetDefaultFill(self):      def GetDefaultFill(self):
120          return self.DefaultData.GetFill()          return self.DefaultGroup.GetProperties().GetFill()
121                    
122      def SetDefaultStroke(self, stroke):      def SetDefaultStroke(self, stroke):
123          self.DefaultData.SetStroke(stroke)          assert(isinstance(stroke, Color))
124          self.SendMessage(LAYER_LEGEND_CHANGED)          self.DefaultGroup.GetProperties().SetStroke(stroke)
125            self.__SendMessage(LAYER_LEGEND_CHANGED)
126                    
127      def GetDefaultStroke(self):      def GetDefaultStroke(self):
128          return self.DefaultData.GetStroke()          return self.DefaultGroup.GetProperties().GetStroke()
129                    
130      def SetDefaultStrokeWidth(self, strokeWidth):      def SetDefaultStrokeWidth(self, strokeWidth):
131          self.DefaultData.SetStrokeWidth(strokeWidth)          assert(isinstance(strokeWidth, IntType))
132          self.SendMessage(LAYER_LEGEND_CHANGED)          self.DefaultGroup.GetProperties().SetStrokeWidth(strokeWidth)
133            self.__SendMessage(LAYER_LEGEND_CHANGED)
134                    
135      def GetDefaultStrokeWidth(self):      def GetDefaultStrokeWidth(self):
136          return self.DefaultData.GetStrokeWidth()          return self.DefaultGroup.GetProperties().GetStrokeWidth()
137                    
138      def AddClassData(self, item):      def AddGroup(self, item):
139          type = item.GetType()          assert(isinstance(item, ClassGroup))
140    
141          if type == ClassData.POINT:          if isinstance(item, ClassGroupDefault):
142              self.points[item.GetValue()] = item              self.SetDefaultGroup(item)
143          elif type == ClassData.RANGE:          elif isinstance(item, ClassGroupSingleton):
144                self.points.append(item)
145            elif isinstance(item, ClassGroupRange):
146              self.ranges.append(item)              self.ranges.append(item)
147          elif type == ClassData.MAP:          elif isinstance(item, ClassGroupMap):
148              self.maps.append(item)              self.maps.append(item)
         elif type == ClassData.DEFAULT:  
             self.DefaultData = item  
149          else:          else:
150              raise ValueError(_("Unrecognized ClassData type %s") % type)              raise ValueError(_("Unrecognized ClassGroup"))
151    
152          self.SendMessage(LAYER_LEGEND_CHANGED)          self.__SendMessage(LAYER_LEGEND_CHANGED)
153    
154      def GetProperties(self, value):      def GetGroup(self, value):
155          """Return the associated data, or the default data.          """Return the associated data, or the default data.
156    
157             The following search technique is used:             The following search technique is used:
# Line 137  class Classification: Line 162  class Classification:
162                     the classification.                     the classification.
163    
164             value -- the value to classify. If there is no mapping,             value -- the value to classify. If there is no mapping,
165                      or value is None, return the default data                      or value is None, return the default properties
                     (which may be None)  
166          """          """
167    
168          if self.field is not None and value is not None:          if self.field is not None and value is not None:
169              #  
170              # check the discrete values              for p in self:
171              #                  if p.Matches(value):
             if self.points.has_key(value):  
                 return self.points[value]  
   
             #  
             # check the ranges  
             #  
             for p in self.ranges:  
                 if p.InRange(value):  
172                      return p                      return p
173    #           #
174    #           # check the discrete values
175    #           #
176    #           if self.points.has_key(value):
177    #               return self.points[value]
178    #           #for p in self.points:
179    #               #if p.Value
180    
181    #           #
182    #           # check the ranges
183    #           #
184    #           for p in self.ranges:
185    #               if p.InRange(value):
186    #                   return p
187    
188    #           #
189    #           # check the maps
190    #           #
191    #           for p in self.maps:
192    #               try:
193    #                   return p.Map(value)
194    #               except: pass
195    
196              #          return self.DefaultGroup
             # check the maps  
             #  
             for p in self.maps:  
                 try:  
                     return p.Map(value)  
                 except: pass  
197    
198          return self.DefaultData      def GetProperties(self, value):
199            return self.GetGroup(value).GetProperties()
200    
201      def TreeInfo(self):      def TreeInfo(self):
202          items = []          items = []
# Line 176  class Classification: Line 209  class Classification:
209                      (text, color.red, color.green, color.blue),                      (text, color.red, color.green, color.blue),
210                      color)                      color)
211    
212          def build_item(data, string):          def build_item(group, string):
213              label = data.GetLabel()              label = group.GetLabel()
214              if label == "":              if label == "":
215                  label = string                  label = string
216              else:              else:
217                  label += " (%s)" % string                  label += " (%s)" % string
218    
219                props = group.GetProperties()
220              i = []              i = []
221              v = data.GetStroke()              v = props.GetStroke()
222              i.append(build_color_item(_("Stroke"), v))              i.append(build_color_item(_("Stroke"), v))
223              v = data.GetStrokeWidth()              v = props.GetStrokeWidth()
224              i.append(_("Stroke Width: %s") % v)              i.append(_("Stroke Width: %s") % v)
225              v = data.GetFill()              v = props.GetFill()
226              i.append(build_color_item(_("Fill"), v))              i.append(build_color_item(_("Fill"), v))
227              return (label, i)              return (label, i)
228    
229          items.append(build_item(self.DefaultData, _("'DEFAULT'")))          for p in self:
230                if isinstance(p, ClassGroupDefault):
231                    items.append(build_item(self.DefaultGroup, _("'DEFAULT'")))
232                elif isinstance(p, ClassGroupSingleton):
233                    items.append(build_item(p, str(p.GetValue())))
234                elif isinstance(p, ClassGroupRange):
235                    items.append(build_item(p, "%s - %s" %
236                                               (p.GetMin(), p.GetMax())))
237    
238          for p in self.points.values():  #       for p in self.points.values():
239              items.append(build_item(p, str(p.GetValue())))  #           items.append(build_item(p, str(p.GetValue())))
240    
241          for p in self.ranges:  #       for p in self.ranges:
242              items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))  #           items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))
243    
244          return (_("Classifications"), items)          return (_("Classification"), items)
245    
246    class ClassIterator:
247    
248  class ClassData:      def __init__(self, default, points, ranges, maps):
249            self.data = [default, points, ranges, maps]
250      INVALID = -1          self.data_iter = iter(self.data)
251      DEFAULT = 0          self.iter = None
252      POINT = 1  
253      RANGE = 2      def __iter__(self):
254      MAP   = 3          return self
255    
256      def __init__(self, type = INVALID, classData = None):      def next(self):
257            if self.iter is None:
258          if classData is not None:              try:
259              self.SetStroke(classData.GetStroke())                  self.data_item = self.data_iter.next()
260              self.SetStrokeWidth(classData.GetStrokeWidth())                  self.iter = iter(self.data_item)
261              self.SetFill(classData.GetFill())              except TypeError:
262                    return self.data_item
263    
264            try:
265                return self.iter.next()
266            except StopIteration:
267                self.iter = None
268                return self.next()
269          
270    class ClassGroupProperties:
271    
272        def __init__(self, prop = None):
273    
274            if prop is not None:
275                self.SetStroke(prop.GetStroke())
276                self.SetStrokeWidth(prop.GetStrokeWidth())
277                self.SetFill(prop.GetFill())
278          else:          else:
279              self.SetStroke(Color.None)              self.SetStroke(Color.None)
280              self.SetStrokeWidth(1)              self.SetStrokeWidth(1)
281              self.SetFill(Color.None)              self.SetFill(Color.None)
282    
         self.type = type  
         self.label = ""  
       
     def GetType(self):  
         return self.type  
   
283      def GetStroke(self):      def GetStroke(self):
284          return self.stroke          return self.stroke
285    
# Line 239  class ClassData: Line 291  class ClassData:
291          return self.stroke_width          return self.stroke_width
292    
293      def SetStrokeWidth(self, stroke_width):      def SetStrokeWidth(self, stroke_width):
294            assert(isinstance(stroke_width, IntType))
295          if (stroke_width < 1):          if (stroke_width < 1):
296              raise ValueError(_("stroke_width < 1"))              raise ValueError(_("stroke_width < 1"))
297    
# Line 251  class ClassData: Line 304  class ClassData:
304          assert(isinstance(fill, Color))          assert(isinstance(fill, Color))
305          self.fill = fill          self.fill = fill
306    
307    
308    class ClassGroup:
309    
310        def __init__(self, label = ""):
311            self.label = label
312    
313      def GetLabel(self):      def GetLabel(self):
314          return self.label          return self.label
315    
316      def SetLabel(self, label):      def SetLabel(self, label):
317          self.label = label          self.label = label
318    
319  class ClassDataDefault(ClassData):      def Matches(self, value):
320      def __init__(self, classData = None):          """This needs to be implemented by all subclasses."""
321          ClassData.__init__(self, ClassData.DEFAULT, classData)          pass
322    
323        def GetProperties(self, value):
324            """This needs to be implemented by all subclasses."""
325            pass
326    
327            
328  class ClassDataPoint(ClassData):  class ClassGroupSingleton(ClassGroup):
329    
330      def __init__(self, value = 0, classData = None):      def __init__(self, value = 0, prop = None, label = ""):
331          ClassData.__init__(self, ClassData.POINT, classData)          ClassGroup.__init__(self, label)
332    
333          self.value = value          self.SetValue(value)
334            self.SetProperties(prop)
335    
336        def __copy__(self):
337            return ClassGroupSingleton(self.value, self.prop, self.label)
338    
339      def GetValue(self):      def GetValue(self):
340          return self.value          return self.value
# Line 274  class ClassDataPoint(ClassData): Line 342  class ClassDataPoint(ClassData):
342      def SetValue(self, value):      def SetValue(self, value):
343          self.value = value          self.value = value
344    
345  class ClassDataRange(ClassData):      def Matches(self, value):
346            return self.value == value
347    
348      def __init__(self, min = 0, max = 1, classData = None):      def GetProperties(self, value = None):
349          ClassData.__init__(self, ClassData.RANGE, classData)          if value is None: return self.prop
350    
351          if min >= max:          if self.Matches(value):
352              raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %              return self.prop
353                               (min, max))          else:
354                return None
355    
356        def SetProperties(self, prop):
357            if prop is None: prop = ClassGroupProperties()
358            assert(isinstance(prop, ClassGroupProperties))
359            self.prop = prop
360    
361    
362    class ClassGroupDefault(ClassGroupSingleton):
363        def __init__(self, prop = None, label = ""):
364            ClassGroupSingleton.__init__(self, 0, prop, label)
365    
366        def __copy__(self):
367            return ClassGroupDefault(self.prop, self.label)
368    
369        def GetProperties(self, value = None):
370            return self.prop
371    
372    class ClassGroupRange(ClassGroup):
373    
374        def __init__(self, min = 0, max = 1, prop = None, label = ""):
375            ClassGroup.__init__(self, label)
376    
377          self.SetRange(min, max)          self.SetRange(min, max)
378            self.SetProperties(prop)
379    
380        def __copy__(self):
381            return ClassGroupRange(self.min, self.max, self.prop, self.label)
382    
383      def GetMin(self):      def GetMin(self):
384          return self.min          return self.min
# Line 298  class ClassDataRange(ClassData): Line 393  class ClassDataRange(ClassData):
393          self.SetRange(self.min, max)          self.SetRange(self.min, max)
394    
395      def SetRange(self, min, max):      def SetRange(self, min, max):
         self.min = min  
         self.max = max  
396          if min >= max:          if min >= max:
397              raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %              raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %
398                               (min, max))                               (min, max))
399            self.min = min
400            self.max = max
401    
402      def GetRange(self):      def GetRange(self):
403          return (self.min, self.max)          return (self.min, self.max)
404    
405      def InRange(self, value):      def Matches(self, value):
406          return self.min <= value < self.max          return self.min <= value < self.max
407    
408  class ClassDataMap(ClassData):      def GetProperties(self, value = None):
409            if value is None: return self.prop
410    
411            if self.Matches(value):
412                return self.prop
413            else:
414                return None
415    
416        def SetProperties(self, prop):
417            if prop is None: prop = ClassGroupProperties()
418            assert(isinstance(prop, ClassGroupProperties))
419            self.prop = prop
420    
421    class ClassGroupMap(ClassGroup):
422    
423      FUNC_ID = "id"      FUNC_ID = "id"
424    
425      def __init__(self, map_type = FUNC_ID, func = None, classData = None):      def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
426          ClassData.__init__(self, ClassData.MAP, classData)          ClassGroup.__init__(self, prop)
427    
428          self.map_type = map_type          self.map_type = map_type
429          self.func = func          self.func = func

Legend:
Removed from v.410  
changed lines
  Added in v.453

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26