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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2728 - (view) (download) (as text)

1 : dpvc 2728 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