1 """
2 PatternGenerator abstract class and basic example concrete class.
3
4 $Id: patterngenerator.py 10672 2009-10-28 01:00:50Z ceball $
5 """
6 __version__='$Revision: 10672 $'
7
8
9 from math import pi
10
11 from numpy import add,subtract,cos,sin
12
13 import param
14 from param.parameterized import ParamOverrides
15
16 from boundingregion import BoundingBox, BoundingRegionParameter
17 from sheetcoords import SheetCoordinateSystem
18 from functionfamily import TransferFn
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
39 """
40 A class hierarchy for callable objects that can generate 2D patterns.
41
42 Once initialized, PatternGenerators can be called to generate a
43 value or a matrix of values from a 2D function, typically
44 accepting at least x and y.
45
46 A PatternGenerator's Parameters can make use of Parameter's
47 precedence attribute to specify the order in which they should
48 appear, e.g. in a GUI. The precedence attribute has a nominal
49 range of 0.0 to 1.0, with ordering going from 0.0 (first) to 1.0
50 (last), but any value is allowed.
51
52 The orientation and layout of the pattern matrices is defined by
53 the SheetCoordinateSystem class, which see.
54
55 Note that not every parameter defined for a PatternGenerator will
56 be used by every subclass. For instance, a Constant pattern will
57 ignore the x, y, orientation, and size parameters, because the
58 pattern does not vary with any of those parameters. However,
59 those parameters are still defined for all PatternGenerators, even
60 Constant patterns, to allow PatternGenerators to be scaled, rotated,
61 translated, etc. uniformly.
62 """
63 __abstract = True
64
65 bounds = BoundingRegionParameter(
66 default=BoundingBox(points=((-0.5,-0.5), (0.5,0.5))),precedence=-1,
67 doc="BoundingBox of the area in which the pattern is generated.")
68
69 xdensity = param.Number(default=10,bounds=(0,None),precedence=-1,doc="""
70 Density (number of samples per 1.0 length) in the x direction.""")
71
72 ydensity = param.Number(default=10,bounds=(0,None),precedence=-1,doc="""
73 Density (number of samples per 1.0 length) in the y direction.
74 Typically the same as the xdensity.""")
75
76 x = param.Number(default=0.0,softbounds=(-1.0,1.0),precedence=0.20,doc="""
77 X-coordinate location of pattern center.""")
78
79 y = param.Number(default=0.0,softbounds=(-1.0,1.0),precedence=0.21,doc="""
80 Y-coordinate location of pattern center.""")
81
82
83 position = param.Composite(attribs=['x','y'],precedence=-1,doc="""
84 Coordinates of location of pattern center.
85 Provides a convenient way to set the x and y parameters together
86 as a tuple (x,y), but shares the same actual storage as x and y
87 (and thus only position OR x and y need to be specified).""")
88
89 orientation = param.Number(default=0.0,softbounds=(0.0,2*pi),precedence=0.40,doc="""
90 Polar angle of pattern, i.e., the orientation in the Cartesian coordinate
91 system, with zero at 3 o'clock and increasing counterclockwise.""")
92
93 size = param.Number(default=1.0,bounds=(0.0,None),softbounds=(0.0,6.0),
94 precedence=0.30,doc="""Determines the overall size of the pattern.""")
95
96 scale = param.Number(default=1.0,softbounds=(0.0,2.0),precedence=0.10,doc="""
97 Multiplicative strength of input pattern, defaulting to 1.0""")
98
99 offset = param.Number(default=0.0,softbounds=(-1.0,1.0),precedence=0.11,doc="""
100 Additive offset to input pattern, defaulting to 0.0""")
101
102 mask = param.Parameter(default=None,precedence=-1,doc="""
103 Optional object (expected to be an array) with which to multiply the
104 pattern array after it has been created, before any output_fns are
105 applied. This can be used to shape the pattern.""")
106
107
108 mask_shape = param.ClassSelector(param.Parameterized,default=None,precedence=0.06,doc="""
109 Optional PatternGenerator used to construct a mask to be applied to
110 the pattern.""")
111
112 output_fns = param.HookList(default=[],class_=TransferFn,precedence=0.08,doc="""
113 Optional function(s) to apply to the pattern array after it has been created.
114 Can be used for normalization, thresholding, etc.""")
115
116 - def __call__(self,**params_to_override):
117 """
118 Call the subclass's 'function' method on a rotated and scaled coordinate system.
119
120 Creates and fills an array with the requested pattern. If
121 called without any params, uses the values for the Parameters
122 as currently set on the object. Otherwise, any params
123 specified override those currently set on the object.
124 """
125 p=ParamOverrides(self,params_to_override)
126
127
128
129
130
131
132 self._setup_xy(p.bounds,p.xdensity,p.ydensity,p.x,p.y,p.orientation)
133 fn_result = self.function(p)
134 self._apply_mask(p,fn_result)
135 result = p.scale*fn_result+p.offset
136
137 for of in p.output_fns:
138 of(result)
139
140 return result
141
142
143 - def _setup_xy(self,bounds,xdensity,ydensity,x,y,orientation):
144 """
145 Produce pattern coordinate matrices from the bounds and
146 density (or rows and cols), and transforms them according to
147 x, y, and orientation.
148 """
149 self.debug(lambda:"bounds=%s, xdensity=%s, ydensity=%s, x=%s, y=%s, orientation=%s"%(bounds,xdensity,ydensity,x,y,orientation))
150
151
152
153
154 x_points,y_points = SheetCoordinateSystem(bounds,xdensity,ydensity).sheetcoordinates_of_matrixidx()
155
156
157
158 self.pattern_x, self.pattern_y = self._create_and_rotate_coordinate_arrays(x_points-x,y_points-y,orientation)
159
160
162 """
163 Function to draw a pattern that will then be scaled and rotated.
164
165 Instead of implementing __call__ directly, PatternGenerator
166 subclasses will typically implement this helper function used
167 by __call__, because that way they can let __call__ handle the
168 scaling and rotation for them. Alternatively, __call__ itself
169 can be reimplemented entirely by a subclass (e.g. if it does
170 not need to do any scaling or rotation), in which case this
171 function will be ignored.
172 """
173 raise NotImplementedError
174
175
188
189
201
202
203
204
205 PatternGenerator.params('mask_shape').class_=PatternGenerator
206
207
208
209
210
211 from numpy.oldnumeric import ones, Float
212
234