1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
49 X = 0
50 Y = 1
51
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
62 """Get membership of value x."""
63 p = self.__points
64
65
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
79 if x1 < x:
80 x0 = x1
81 continue
82
83 if x1 == x:
84 y = p[i][Polygon.Y]
85
86 for j in range(i+1, len(p)):
87 if p[j][Polygon.X] > x:
88 break
89 else:
90
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
98 if x1 == x0:
99 return max(y0, y1)
100 return y0+(y1-y0)/(x1-x0)*(x-x0)
101 return 0.0
102
103
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
122 if where == self.END:
123 self.__points.append((x, y))
124 else:
125 self.__points.insert(0, (x, y))
126
127 self.__points.sort(key = lambda p:p[Polygon.X])
128
129
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
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
151
153 """Reset polygon to zero."""
154 del self.__points[:]
155
156
157 @prop
159 """points of the polygon.
160 @type: list of 2-tuple (x,y)"""
161 def fget(self):
162 import copy
163 return copy.deepcopy(self.__points)
164 return locals()
165
166
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
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
204 """Return center of gravity."""
205 if len(self.__points) <=1 :
206
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
216
217
218
219 x0_2 = x0*x0
220 x0_3 = x0_2*x0
221
222
223 for x1, y1 in iterator:
224 if x1 != x0:
225 x1_2 = x1*x1
226 x1_3 = x1_2*x1
227 area += (y0+y1)/2.0*(x1-x0)
228
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
234 break
235
236 if area == 0.0:
237 raise FuzzyException("no COG calculable: polygon area is zero!")
238 COG /= area
239 return COG
240
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