[system] / trunk / pg / macros / parserParametricLine.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/parserParametricLine.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2728 - (download) (as text) (annotate)
Sat Sep 4 20:28:33 2004 UTC (15 years, 5 months ago) by dpvc
File size: 3845 byte(s)
This file defines a ParametricLine class that provides an answser
checker for lines in any dimension given parametrically.  The answer
checker will recognize the line even if the point and direction vector
used by the student are not the same as the ones used by the
professor.

See the comments within the file for examples of how to use it.

    1 loadMacros('Parser.pl');
    2 
    3 sub _parserParametricLine_init {}; # don't reload this file
    4 
    5 ######################################################################
    6 #
    7 #  This is a Parser class that implements parametric lines as
    8 #  a subclass of the Formula class.  The standard ->cmp routine
    9 #  will work for this, provided we define the compare() function
   10 #  needed by the overloaded ==.  We assign the special precedence
   11 #  so that overloaded operations will be promoted to the ones below.
   12 #
   13 #  Use ParametricLine(point,vector) or ParametricLine(formula)
   14 #  to create a ParametricLine object.  You can pass an optional
   15 #  additional parameter that indicated the variable to use for the
   16 #  parameter for the line.
   17 #
   18 #  Usage examples:
   19 #
   20 #      $L = ParametricLine(Point(3,-1,2),Vector(1,1,3));
   21 #      $L = ParametricLine([3,-1,2],[1,1,3]);
   22 #      $L = ParametricLine("<t,1-t,2t-3>");
   23 #
   24 #      $p = Point(3,-1,2); $v = Vector(1,1,3);
   25 #      $L = ParametricLine($p,$v);
   26 #
   27 #      $t = Formula('t'); $p = Point(3,-1,2); $v = Vector(1,1,3);
   28 #      $L = ParametricLine($p+$t*$v);
   29 #
   30 #      Context()->constants->are(a=>1+pi^2); # won't guess this value
   31 #      $L = ParametricLine("(a,2a,-1) + t <1,a,a^2>");
   32 #
   33 #  Then use
   34 #
   35 #     ANS($L->cmp);
   36 #
   37 #  to get the answer checker for $L.
   38 #
   39 
   40 #
   41 #  Define a new context for lines
   42 #
   43 $context{ParametricLine} = Context("Vector")->copy();
   44 $context{ParametricLine}->variables->are(t=>'Real');
   45 $context{ParametricLine}->{precedence}{ParametricLine} =
   46   $context{ParametricLine}->{precedence}{special};
   47 #
   48 #  Make it active
   49 #
   50 Context("ParametricLine");
   51 
   52 #
   53 #  Syntactic sugar
   54 #
   55 sub ParametricLine {ParametricLine->new(@_)}
   56 
   57 #
   58 #  Define the subclass of Formula
   59 #
   60 package ParametricLine;
   61 our @ISA = qw(Value::Formula);
   62 
   63 sub new {
   64   my $self = shift; my $class = ref($self) || $self;
   65   my ($p,$v,$line,$t);
   66   return shift if scalar(@_) == 1 && ref($_[0]) eq $class;
   67   $_[0] = Value::Point->new($_[0]) if ref($_[0]) eq 'ARRAY';
   68   $_[1] = Value::Vector->new($_[1]) if ref($_[1]) eq 'ARRAY';
   69   if (scalar(@_) >= 2 && Value::class($_[0]) eq 'Point' &&
   70                          Value::class($_[1]) eq 'Vector') {
   71     $p = shift; $v = shift;
   72     $t = shift || Value::Formula->new('t');
   73     $line = $p + $t*$v;
   74   } else {
   75     $line = Value::Formula->new(shift);
   76     Value::Error("Your formula doesn't look like a parametric line")
   77       unless $line->type eq 'Vector';
   78     $t = shift || (keys %{$line->{variables}})[0];
   79     $p = Value::Point->new($line->eval($t=>0));
   80     $v = $line->eval($t=>1) - $p;
   81     Value::Error("Your formula isn't linear in the variable $t")
   82       unless $line == $p + Value::Formula->new($t) * $v;
   83   }
   84   Value::Error("The direction vector for a parametric line can't be the zero vector")
   85     if ($v->norm == 0);
   86   $line->{p} = $p; $line->{v} = $v;
   87   $line->{isValue} = $line->{isFormula} = 1;
   88   return bless $line, $class;
   89 }
   90 
   91 #
   92 #  Two parametric lines are equal if they have
   93 #  parallel direction vectors and either the same
   94 #  points or the vector between the points is
   95 #  parallel to the (common) direction vector.
   96 #
   97 sub compare {
   98   my ($l,$r,$flag) = @_;
   99   $r = ParametricLine->new($r);
  100   if ($flag) {my $tmp = $l; $l = $r; $r = $tmp}
  101   my ($lp,$lv) = ($l->{p},$l->{v});
  102   my ($rp,$rv) = ($r->{p},$r->{v});
  103   return $lv <=> $rv unless ($lv->isParallel($rv));
  104   return 0 if $lp == $rp || $lv->isParallel($rp-$lp);
  105   return $lp <=> $rp;
  106 }
  107 
  108 sub cmp_class {'a Parametric Line'};
  109 
  110 sub cmp_defaults {(
  111   shift->SUPER::cmp_defaults,
  112   showEqualErrors => 0,  # don't show problems evaluating student answer
  113   ignoreInfinity => 0,   # report infinity as an error
  114 )}
  115 
  116 #
  117 #  Report some errors that were stopped by the showEqualErrors=>0 above.
  118 #
  119 sub cmp_postprocess {
  120   my $self = shift; my $ans = shift;
  121   $self->cmp_error($ans)
  122     if $$Value::context->{error}{message} =~ m/^Your formula isn't linear/;
  123 }
  124 
  125 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9