[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 4385 - (download) (as text) (annotate)
Wed Aug 16 01:42:46 2006 UTC (13 years, 3 months ago) by dpvc
File size: 4165 byte(s)
Report the objec type better in parser error messages.

    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 $context{ParametricLine}->reduction->set('(-x)-y'=>0);
   48 #
   49 #  Make it active
   50 #
   51 Context("ParametricLine");
   52 
   53 #
   54 #  Syntactic sugar
   55 #
   56 sub ParametricLine {ParametricLine->new(@_)}
   57 
   58 #
   59 #  Define the subclass of Formula
   60 #
   61 package ParametricLine;
   62 our @ISA = qw(Value::Formula);
   63 
   64 sub new {
   65   my $self = shift; my $class = ref($self) || $self;
   66   my ($p,$v,$line,$t);
   67   return shift if scalar(@_) == 1 && ref($_[0]) eq $class;
   68   $_[0] = Value::Point->new($_[0]) if ref($_[0]) eq 'ARRAY';
   69   $_[1] = Value::Vector->new($_[1]) if ref($_[1]) eq 'ARRAY';
   70   if (scalar(@_) >= 2 && Value::class($_[0]) eq 'Point' &&
   71                          Value::class($_[1]) eq 'Vector') {
   72     $p = shift; $v = shift;
   73     $t = shift || Value::Formula->new('t');
   74     $line = $p + $t*$v;
   75   } else {
   76     $line = Value::Formula->new(shift);
   77     Value::Error("Your formula doesn't look like a parametric line")
   78       unless $line->type eq 'Vector';
   79     $t = shift || (keys %{$line->{variables}})[0];
   80     Value::Error("A line can't be just a constant vector") unless $t;
   81     $p = Value::Point->new($line->eval($t=>0));
   82     $v = Value::Vector->new($line->eval($t=>1) - $p);
   83     Value::Error("Your formula isn't linear in the variable %s",$t)
   84       unless $line == $p + Value::Formula->new($t) * $v;
   85   }
   86   Value::Error("The direction vector for a parametric line can't be the zero vector")
   87     if ($v->norm == 0);
   88   $line->{p} = $p; $line->{v} = $v;
   89   $line->{isValue} = $line->{isFormula} = 1;
   90   return bless $line, $class;
   91 }
   92 
   93 #
   94 #  Two parametric lines are equal if they have
   95 #  parallel direction vectors and either the same
   96 #  points or the vector between the points is
   97 #  parallel to the (common) direction vector.
   98 #
   99 sub compare {
  100   my ($l,$r,$flag) = @_;
  101   if ($l->promotePrecedence($r)) {return $r->compare($l,!$flag)}
  102   $r = ParametricLine->new($r);
  103   if ($flag) {my $tmp = $l; $l = $r; $r = $tmp}
  104   my ($lp,$lv) = ($l->{p},$l->{v});
  105   my ($rp,$rv) = ($r->{p},$r->{v});
  106   return $lv <=> $rv unless ($lv->isParallel($rv));
  107   return 0 if $lp == $rp || $lv->isParallel($rp-$lp);
  108   return $lp <=> $rp;
  109 }
  110 
  111 sub cmp_class {'a Parametric Line'};
  112 sub showClass {shift->cmp_class};
  113 
  114 sub cmp_defaults {(
  115   shift->SUPER::cmp_defaults,
  116   showEqualErrors => 0,  # don't show problems evaluating student answer
  117   ignoreInfinity => 0,   # report infinity as an error
  118 )}
  119 
  120 #
  121 #  Report some errors that were stopped by the showEqualErrors=>0 above.
  122 #
  123 sub cmp_postprocess {
  124   my $self = shift; my $ans = shift;
  125   my $error = $$Value::context->{error}{message};
  126   $self->cmp_error($ans)
  127     if $error =~ m/^(Your formula (isn't linear|doesn't look)|A line can't|The direction vector)/;
  128 }
  129 
  130 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9