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

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

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;
```