Package fuzzy :: Package set :: Module Polygon
[hide private]
[frames] | no frames]

Source Code for Module fuzzy.set.Polygon

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (C) 2009  Rene Liebscher 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify it under 
  6  # the terms of the GNU Lesser General Public License as published by the Free  
  7  # Software Foundation; either version 3 of the License, or (at your option) any 
  8  # later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but WITHOUT  
 11  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 12  # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
 13  # details. 
 14  #  
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with this program; if not, see <http://www.gnu.org/licenses/>.  
 17  # 
 18   
 19  """Represents a fuzzy set, which membership function 
 20  is the shape of a polygon. For example: triangle, 
 21  trapezoid, rectangle, or something similar.""" 
 22   
 23  __revision__ = "$Id: Polygon.py,v 1.25 2010-10-29 19:24:41 rliebscher Exp $" 
 24   
 25   
 26  from fuzzy.set.Set import Set 
 27  from fuzzy.utils import prop 
 28  from fuzzy.Exception import FuzzyException 
29 30 -class Polygon(Set):
31 r"""Represents a fuzzy set, which membership function 32 is the shape of a polygon. For example: triangle, 33 trapezoid, rectangle, or something similar. 34 35 If you need something similar to ZFunction or SFunction, 36 use this class directly by building it from two points.:: 37 38 ---* *--- 39 \ / 40 \ OR / 41 \ / 42 *--- ---* 43 44 See also U{http://pyfuzzy.sourceforge.net/demo/set/Polygon%20(Demo).png} 45 46 """ 47 48 # indices for coordinate tuple 49 X = 0 #: index of x value in tuple 50 Y = 1 #: index of y value in tuple 51
52 - def __init__(self, points=None):
53 """Initialize with given sorted list of (x,y) values 54 55 @param points: sorted list of 2-tuples of (x,y) values 56 @type points: list of 2-tuples (float,float) 57 """ 58 super(Polygon, self).__init__() 59 self.__points = [(float(x),float(y)) for (x,y) in (points or [])]
60
61 - def __call__(self, x):
62 """Get membership of value x.""" 63 p = self.__points 64 65 # first handle obvious cases 66 if p == []: 67 return 0.0 68 if len(p) == 1: 69 return p[0][Polygon.Y] 70 if x < p[0][Polygon.X]: 71 return p[0][Polygon.Y] 72 if x > p[-1][Polygon.X]: 73 return p[-1][Polygon.Y] 74 75 x0 = p[0][Polygon.X] 76 for i in range(1, len(p)): 77 x1 = p[i][Polygon.X] 78 # found right interval border 79 if x1 < x: 80 x0 = x1 81 continue 82 # if we want a x values which is a polygon point ... 83 if x1 == x: 84 y = p[i][Polygon.Y] 85 # ... check following points for same x-value ... 86 for j in range(i+1, len(p)): 87 if p[j][Polygon.X] > x: 88 break 89 else: 90 # ... and use the maximum value 91 y_ = p[j][Polygon.Y] 92 if y_ > y: 93 y = y_ 94 return y 95 y0 = p[i-1][Polygon.Y] 96 y1 = p[i][Polygon.Y] 97 # interpolate value in interval 98 if x1 == x0: # should never happen 99 return max(y0, y1) 100 return y0+(y1-y0)/(x1-x0)*(x-x0) 101 return 0.0 # should never be reached
102 103 # at which end do we insert or remove a point 104 BEGIN = 0 105 END = 1 106
107 - def add(self, x, y, where=END):
108 r"""Add a new point to the polygon. 109 The parameter where controls at which end 110 it is inserted. (The points are always sorted, but 111 if two have the same x value their order is important. 112 For example: adding a second point(y=0) in the middle:: 113 now where=END where=BEGIN 114 *--* *--* * * 115 \ | \ |\ 116 \ | \| \ 117 * *--* * * 118 """ 119 x = float(x) 120 y = float(y) 121 # quick and dirty implementation 122 if where == self.END: 123 self.__points.append((x, y)) 124 else: 125 self.__points.insert(0, (x, y)) 126 # use only x value for sorting 127 self.__points.sort(key = lambda p:p[Polygon.X])
128 129
130 - def remove(self, x, where=END):
131 r"""Remove a point from the polygon. 132 The parameter where controls at which end 133 it is removed. (The points are always sorted, but 134 if two have the same x value their order is important. 135 For example: removing the second point in the middle:: 136 now where=END where=BEGIN 137 *--* *--* * 138 | \ \ 139 | \ \ 140 *--* * *--* 141 """ 142 # quick and dirty implementation 143 range_p = range(len(self.__points)) 144 if where == self.END: 145 range_p.reverse() 146 for i in range_p: 147 if self.__points[i][Polygon.X] == x: 148 self.__points.remove(i) 149 return
150 #raise FuzzyException("Not in points list") 151
152 - def clear(self):
153 """Reset polygon to zero.""" 154 del self.__points[:]
155 156 # pylint: disable=E0211,W0212 157 @prop
158 - def points(): #@NoSelf
159 """points of the polygon. 160 @type: list of 2-tuple (x,y)""" 161 def fget(self): # pylint: disable=W0612,C0111 162 import copy 163 return copy.deepcopy(self.__points)
164 return locals() 165 166
167 - def getValuesX(self):
168 """Return sequence of x-values for set.""" 169 previous = None 170 for x,_ in self.__points: 171 if x != previous: 172 yield x 173 previous = x
174
175 - def getValuesXY(self, flat = True):
176 """Return sequence of (x,y)-values for set. 177 In case of vertical slopes, y is a tuple of y-values for flat = False. 178 Otherwise several (x,y)-values will be generated having identical x-values.""" 179 current = None 180 values = [] 181 for x,y in self.__points: 182 if x != current: 183 if current is None: 184 pass 185 else: 186 if flat: 187 for y_ in values: 188 yield current,y_ 189 else: 190 yield current,values 191 values = [] 192 current = x 193 values.append(y) 194 else: 195 values.append(y) 196 if len(values) > 0: 197 if flat: 198 for y_ in values: 199 yield current,y_ 200 else: 201 yield current,values
202
203 - def getCOG(self):
204 """Return center of gravity.""" 205 if len(self.__points) <=1 : 206 #return 0.0 207 raise FuzzyException("no COG calculable: single point = constant value") 208 if self.__points[0][Polygon.Y] > 0 or self.__points[-1][Polygon.Y] > 0: 209 raise FuzzyException("no COG calculable: end points of polygon not y=0.0") 210 area = 0. 211 COG = 0. 212 213 iterator = iter(self.__points) 214 for x0, y0 in iterator: 215 # only to initialize x0,y0 216 # up to 2.6 one could do this with x0, y0 in iterator.next() 217 # but 3.x doesn't support no longer the next() method 218 # TODO: But it supports a built-in function next()! 219 x0_2 = x0*x0 # =x² 220 x0_3 = x0_2*x0 # =x³ 221 222 # and now use the rest of the iterator 223 for x1, y1 in iterator: 224 if x1 != x0: # vertical slopes don't have an area to x.axis 225 x1_2 = x1*x1 226 x1_3 = x1_2*x1 227 area += (y0+y1)/2.0*(x1-x0) # area of trapezoid 228 # Integral( x*f(x) ) 229 COG += y0/2.0*(x1_2-x0_2)+(y1-y0)/(x1-x0)*(x1_3/3.0-x0_3/3.0-x1_2*x0/2.0+x0_3/2.0) 230 x0, x0_2, x0_3 = x1, x1_2, x1_3 231 y0 = y1 232 233 # not really necessary as the above for loop should have exhausted the iterator 234 break 235 236 if area == 0.0: 237 raise FuzzyException("no COG calculable: polygon area is zero!") 238 COG /= area 239 return COG # XXX
240
241 - def __repr__(self):
242 """Return representation of instance. 243 244 @return: representation of instance 245 @rtype: string 246 """ 247 return "%s.%s(points=%s)" % ( 248 self.__class__.__module__, 249 self.__class__.__name__, 250 repr(self.__points), 251 )
252