[system] / trunk / pg / lib / VectorField.pm Repository:
ViewVC logotype

Annotation of /trunk/pg/lib/VectorField.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2274 - (view) (download) (as text)

1 : sh002i 1050
2 :     =head1 NAME
3 :    
4 :     VectorField
5 :    
6 :     =head1 SYNPOSIS
7 :    
8 :     use Carp;
9 :     use GD;
10 :     use WWPlot;
11 :     use Fun;
12 :     $fn = new Fun( rule_reference);
13 :     $fn = new Fun( rule_reference , graph_reference);
14 :     $fn = new Fun ( x_rule_ref, y_rule_ref );
15 :     $fn = new Fun ( x_rule_ref, y_rule_ref, graph_ref );
16 :    
17 :     =head1 DESCRIPTION
18 :    
19 :     This module defines a phase plane vector field. It can also be used to define direction fields
20 :     for differenential equations.
21 :    
22 :     The following functions are provided:
23 :    
24 :     =head2 new (direction field version)
25 :    
26 : apizer 1079 =over 4
27 : sh002i 1050
28 :     =item $fn = new VectorField( dy_rule_ref);
29 :    
30 :     rule_reference is a reference to a subroutine which accepts a pair of numerical values
31 :     and returns a numerical value.
32 : apizer 1079 The Fun object will draw the direction field associated with this subroutine.
33 : sh002i 1050
34 :     The new method returns a reference to the vector field object.
35 :    
36 :     =item $fn = new Fun( rule_reference , graph_reference);
37 :    
38 :     The vector field is also placed into the printing queue of the graph
39 : apizer 1079 object pointed to by graph_reference and the
40 : sh002i 1050 domain of the vector field object is set to the domain of the graph.
41 :    
42 :     =back
43 :    
44 : apizer 1079 =head2 new (phase plane version)
45 : sh002i 1050
46 : apizer 1079 =over 4
47 : sh002i 1050
48 :     =item $fn = new VectorField ( dx_rule_ref, dy_rule_ref );
49 :    
50 :     A vector field object is created where the subroutines refered to by dx_rule_ref and dy_rule_ref define
51 : apizer 1079 the x and y components of the vector field at (x,y). Both subroutines must be functions of two variables.
52 : sh002i 1050
53 :     =item $fn = new VectorField ( x_rule_ref, y_rule_ref, graph_ref );
54 :    
55 :     This variant inserts the vector field object into the graph object referred to by graph_ref. The domain
56 :     of the vector field object is set to the domain of the graph.
57 :    
58 :     =back
59 :    
60 :     =head2 Properites
61 :    
62 : apizer 1079 All of the properties are set using the construction $new_value = $fn->property($new_value)
63 : sh002i 1050 and read using $current_value = $fn->property()
64 :    
65 : apizer 1079 =over 4
66 : sh002i 1050
67 :     =item xmin, xmax, ymin, ymax
68 :    
69 : apizer 1079 The domain of the vector field defined by these values.
70 : sh002i 1050
71 :     =item x_steps y_steps
72 :    
73 :     This gives the number of intervals in the x direction (respectively the y direction) for plotting the vector
74 :     field arrows.
75 :    
76 :     =item arrow_color, dot_color
77 :    
78 :     The colors of the arrow bodies and the dot "base" of the arrow are
79 : apizer 1079 specified by a word such as 'orange' or 'yellow'.
80 : sh002i 1050 C<$vf->arrow_color('blue'); $vf->dot_color('red');> sets the drawing color to blue for the arrow body, with
81 :     a red dot at the base of the arrow. The RGB values for the color are defined in the graph
82 :     object in which the vector field is drawn. If the color, e.g. 'mauve', is not defined by the graph object
83 :     then the function is drawn using the color 'default_color' which is always defined (and usually black).
84 :    
85 :     =item dx_rule
86 :    
87 : apizer 1079 A reference to the subroutine used to calculate the dx value of the phase plane field.
88 : sh002i 1050 This is set to the constant function 1
89 :     when using the function object in direction field mode.
90 :    
91 :     =item dy_rule
92 :    
93 :     A reference to the subroutine used to calculate the dy value of the phase plane field.
94 :    
95 :     =item arrow_weight, dot_weight
96 :    
97 :     The width in pixels of the pen used to draw the arrow (respectively the dot).
98 :    
99 :     =back
100 :    
101 :     =head2 Actions which affect more than one property.
102 :    
103 :     =over 4
104 :    
105 :    
106 :     =item domain
107 :    
108 :     $array_ref = $fn->domain(-1,-2,1,2) sets xmin to -1, ymin to -2, xmax to 1, and ymax to 2.
109 :    
110 :    
111 :     =item draw
112 :    
113 : apizer 1079 $fn->draw($graph_ref) draws the vector field in the graph object pointed to by $graph_ref.
114 : sh002i 1050
115 :     The graph object must
116 : apizer 1079 respond to the methods below. The draw call is mainly for internal
117 : sh002i 1050 use by the graph object. Most users will not
118 :     call it directly.
119 :    
120 : apizer 1079 =over 4
121 : sh002i 1050
122 : apizer 1079 =item $graph_ref->{colors}
123 : sh002i 1050
124 :     a hash containing the defined colors
125 :    
126 : apizer 1079 =item $graph_ref ->im
127 : sh002i 1050
128 :     a GD image object
129 :    
130 :     =item $graph_ref->lineTo(x,y, color_number)
131 :    
132 :     draw line to the point (x,y) from the current position using the specified color. To obtain the color number
133 :     use a construction such as C<$color_number = $graph_ref->{colors}{'blue'};>
134 :    
135 :     =item $graph_ref->lineTo(x,y,gdBrushed)
136 :    
137 :     draw line to the point (x,y) using the pattern set by SetBrushed (see GD documentation)
138 :    
139 :     =item $graph_ref->moveTo(x,y)
140 :    
141 :     set the current position to (x,y)
142 :    
143 : apizer 1079 =back
144 : sh002i 1050
145 :     =back
146 :    
147 :     =cut
148 :    
149 :     BEGIN {
150 :     be_strict(); # an alias for use strict. This means that all global variable must contain main:: as a prefix.
151 :     }
152 :    
153 :     package VectorField;
154 :    
155 :    
156 :     #use "WWPlot.pm";
157 :     #Because of the way problem modules are loaded 'use' is disabled.
158 :    
159 :    
160 :    
161 :    
162 :    
163 :     @VectorField::ISA = qw(WWPlot);
164 :     # import gdBrushed from GD. It unclear why, but a good many global methods haven't been imported.
165 :     sub gdBrushed {
166 :     &GD::gdBrushed();
167 :     }
168 :    
169 : apizer 1079 my $GRAPH_REFERENCE = "WWPlot";
170 : sh002i 1050 my $VECTORFIELD_REFERENCE = "VectorField";
171 :    
172 :     my %fields =(
173 : apizer 1079 xmin => -4,
174 : sh002i 1050 xmax => 4,
175 :     ymin => -4,
176 :     ymax => 4,
177 :     x_steps => 10,
178 :     y_steps => 10,
179 :     arrow_color => 'blue',
180 :     arrow_weight => 1, #line thickness
181 :     dot_color => 'red',
182 :     dot_radius => 1.5,
183 :     dt => 0.1,
184 :     dx_rule => sub{1;},
185 :     dy_rule => sub{1;},
186 : apizer 1079 rf_arrow_length => sub{my($dx,$dy)=@_;
187 :     return(0) if sqrt($dx**2 + $dy**2) ==0;
188 : sh002i 1050 0.5*1/sqrt($dx**2 + $dy**2);
189 :     },
190 :    
191 :     );
192 :    
193 :    
194 :     sub new {
195 :     my $class = shift;
196 :    
197 : apizer 1079 my $self = {
198 : sh002i 1050 _permitted => \%fields,
199 :     %fields,
200 :     };
201 : apizer 1079
202 : sh002i 1050 bless $self, $class;
203 :     $self -> _initialize(@_);
204 :     return $self;
205 :     }
206 :    
207 :     sub identity { # the identity function
208 :     shift;
209 :     }
210 :    
211 :    
212 : apizer 1079 sub _initialize {
213 : sh002i 1050 my $self = shift;
214 :     my ($xrule,$yrule, $rule,$graphRef);
215 :     my @input = @_;
216 :     if (ref($input[$#input]) eq $GRAPH_REFERENCE ) {
217 : apizer 1079 $graphRef = pop @input; # get the last argument if it refers to a graph.
218 : sh002i 1050 $graphRef->fn($self); # Install this vector field in the graph.
219 :     $self->{xmin} = $graphRef->{xmin};
220 :     $self->{xmax} = $graphRef->{xmax};
221 :     $self->{ymin} = $graphRef->{ymin};
222 :     $self->{ymax} = $graphRef->{ymax};
223 : apizer 1079 }
224 : sh002i 1050 if ( @input == 1 ) { # only one argument left -- this is a non parametric function
225 :     $rule = $input[0];
226 :     if ( ref($rule) eq $VECTORFIELD_REFERENCE ) { # clone another function
227 :     my $k;
228 :     foreach $k (keys %fields) {
229 :     $self->{$k} = $rule->{$k};
230 :     }
231 :     } else {
232 :     $self->{dx_rule} = sub {1; };
233 :     $self->{dy_rule} = $input[0] ;
234 :     }
235 :     } elsif (@input == 2 ) { # two arguments -- parametric functions
236 :     $self->{dx_rule} = $input[0] ;
237 :     $self->{dy_rule} = $input[1] ;
238 : apizer 1079
239 : sh002i 1050 } else {
240 : sh002i 2274 die "VectorField.pm:_initialize: Can't call VectorField with more than two arguments";
241 : apizer 1079 }
242 : sh002i 1050 }
243 :     sub draw {
244 : apizer 1079 my $self = shift; # this function
245 : sh002i 1050 my $g = shift; # the graph containing the function.
246 :     warn "This vector field is not being called from an enclosing graph" unless defined($g);
247 :     my $arrow_color; # get color scheme from graph
248 :     if ( defined( $g->{'colors'}{$self->arrow_color} ) ) {
249 : apizer 1079 $arrow_color = $g->{'colors'}{$self->arrow_color};
250 : sh002i 1050 } else {
251 :     $arrow_color = $g->{'colors'}{'blue'}; # what you do if the color isn't there
252 :     }
253 :     my $dot_color = $self ->dot_color; # colors are defined differently for Circles, then for lines.
254 :     my $dot_radius = $self->dot_radius;
255 :     my $brush = new GD::Image($self->arrow_weight,$self->arrow_weight);
256 :     my $brush_color = $brush->colorAllocate($g->im->rgb($arrow_color)); # transfer color
257 :     $g->im->setBrush($brush);
258 :     my $x_steps = 10;
259 :     my $xmin = $self->xmin;
260 :     my $x_stepsize = ( $self->xmax - $self->xmin )/$x_steps;
261 :     my $y_steps = 10;
262 :     my $ymin = $self->ymin;
263 :     my $y_stepsize = ( $self->ymax - $self->ymin )/$y_steps;
264 :     my $dt = $self->dt;
265 :     my $rf_arrow_length = $self->rf_arrow_length;
266 :    
267 :     foreach my $i (0..$x_steps) {
268 :     my $x = $xmin + $i*$x_stepsize;
269 :     foreach my $j (0..$y_steps) {
270 :     my $y = $ymin + $j*$y_stepsize;
271 :     my $dx = $dt*&{$self->dx_rule}($x,$y);
272 :     my $dy = $dt*&{$self->dy_rule}($x,$y);
273 :     $g->moveTo($x,$y);
274 :     $g->stamps(new Circle($x, $y, $dot_radius,$dot_color,$dot_color) );
275 :     $g->lineTo($x+$dx*&$rf_arrow_length($dx,$dy), $y+$dy*&$rf_arrow_length($dx,$dy),gdBrushed);
276 : apizer 1079
277 : sh002i 1050 }
278 : apizer 1079 }
279 : sh002i 1050 }
280 :    
281 :     sub domain {
282 :     my $self =shift;
283 :     my @inputs = @_;
284 :     $self->{xmin} = $inputs[0];
285 :     $self->{ymin} = $inputs[1];
286 :     $self->{xmax} = $inputs[2];
287 : apizer 1079 $self->{ymax} = $inputs[3];
288 : sh002i 1050 }
289 :    
290 :    
291 :     sub DESTROY {
292 :     # doing nothing about destruction, hope that isn't dangerous
293 :     }
294 :    
295 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9