[system] / trunk / pg / macros / parserParametricLine.pl Repository: Repository Listing bbplugincoursesdistsnplrochestersystemwww

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

Tue Oct 19 00:15:54 2004 UTC (15 years, 4 months ago) by dpvc
File size: 4063 byte(s)
```Handle error messages better.  Produce an error if the student answer
is a constant vector.  Prevent reduction of some negatives in order to
avoid -(a+bt).  Allow students to provide answer in terms of points
rather than vectors.
```

```    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 \$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   \$r = ParametricLine->new(\$r);
102   if (\$flag) {my \$tmp = \$l; \$l = \$r; \$r = \$tmp}
103   my (\$lp,\$lv) = (\$l->{p},\$l->{v});
104   my (\$rp,\$rv) = (\$r->{p},\$r->{v});
105   return \$lv <=> \$rv unless (\$lv->isParallel(\$rv));
106   return 0 if \$lp == \$rp || \$lv->isParallel(\$rp-\$lp);
107   return \$lp <=> \$rp;
108 }
109
110 sub cmp_class {'a Parametric Line'};
111
112 sub cmp_defaults {(
113   shift->SUPER::cmp_defaults,
114   showEqualErrors => 0,  # don't show problems evaluating student answer
115   ignoreInfinity => 0,   # report infinity as an error
116 )}
117
118 #
119 #  Report some errors that were stopped by the showEqualErrors=>0 above.
120 #
121 sub cmp_postprocess {
122   my \$self = shift; my \$ans = shift;
123   my \$error = \$\$Value::context->{error}{message};
124   \$self->cmp_error(\$ans)
125     if \$error =~ m/^(Your formula (isn't linear|doesn't look)|A line can't|The direction vector)/;
126 }
127
128 1;
```