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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1050 - (download) (as text) (annotate)
Fri Jun 6 21:39:42 2003 UTC (16 years, 8 months ago) by sh002i
File size: 8113 byte(s)
moved PG modules and macro files from webwork-modperl to pg
-sam

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9