--- loncom/homework/functionplotresponse.pm 2010/10/09 17:43:25 1.10 +++ loncom/homework/functionplotresponse.pm 2010/10/28 00:27:56 1.16 @@ -1,7 +1,7 @@ # LearningOnline Network with CAPA # option list style responses # -# $Id: functionplotresponse.pm,v 1.10 2010/10/09 17:43:25 www Exp $ +# $Id: functionplotresponse.pm,v 1.16 2010/10/28 00:27:56 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -33,7 +33,7 @@ use Apache::lonlocal; use Apache::lonnet; BEGIN { - &Apache::lonxml::register('Apache::functionplotresponse',('functionplotresponse','backgroundplot','spline')); + &Apache::lonxml::register('Apache::functionplotresponse',('functionplotresponse','backgroundplot','spline','splinerule')); } # @@ -101,12 +101,25 @@ ENDDEFAULTPARAMETERS # sub init_script { - if ($Apache::functionplotresponse::callscripts) { + if ($#Apache::functionplotresponse::callscripts>=0) { + my $script=''; + foreach my $id (@Apache::functionplotresponse::callscripts) { + $script.="if (param=='applet_$id') { loaded_$id=true; }\n"; + } + $script.="if (".join(' && ',map { "loaded_$_" } (@Apache::functionplotresponse::callscripts)). + ") { setTimeout('ggbInitAll()',20) }\n"; + my $calls=join("\n",map { "ggbInit_$_();" } (@Apache::functionplotresponse::callscripts)); return (< // @@ -178,10 +191,10 @@ sub generate_input_field { # sub new_coordinate { my ($id,$variable,$x,$y)=@_; - if ($Apache::functionplotresponse::previous{&field_name($id,$variable,'x')}) { + if (defined($Apache::functionplotresponse::previous{&field_name($id,$variable,'x')})) { $x=$Apache::functionplotresponse::previous{&field_name($id,$variable,'x')}; } - if ($Apache::functionplotresponse::previous{&field_name($id,$variable,'y')}) { + if (defined($Apache::functionplotresponse::previous{&field_name($id,$variable,'y')})) { $y=$Apache::functionplotresponse::previous{&field_name($id,$variable,'y')}; } &generate_input_field($id,$variable,$x,$y); @@ -194,14 +207,16 @@ sub new_coordinate { # sub start_init_script { my ($id)=@_; -# Add a line to ggbOnInit-function which calls the right function based on parameter passed from GeoGebra - $Apache::functionplotresponse::callscripts.="if (param=='applet_$id') { ggbInit_$id(); }\n"; +# Add id to the list of ggbInit_$id functions that need to be called + push(@Apache::functionplotresponse::callscripts,$id); # ... and open this function return (< // +# +sub start_splinerule { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result=''; + my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1]; + if ($target eq 'edit') { + $result=&Apache::edit::tag_start($target,$token,'Spline Evaluation Rule'). + &Apache::edit::end_row(); + } + return $result; } +sub end_splinerule { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result=''; + if ($target eq 'edit') { + $result=&Apache::edit::end_table(); + } + return $result; +} + + # # # @@ -291,36 +369,70 @@ sub end_backgroundplot { # sub start_spline { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval); - $Apache::functionplotresponse::counter++; - $label=~s/\W//gs; - unless ($label) { $label='S'.$Apache::functionplotresponse::counter; } - - my $order=&Apache::lonxml::get_param('order',$parstack,$safeeval); - if ($order<2) { $order=2; } - if ($order>8) { $order=8; } - $Apache::functionplotresponse::splineorder{$label}=$order; - - my $x=&Apache::lonxml::get_param('initx',$parstack,$safeeval); - unless ($x) { $x=0; } - $Apache::functionplotresponse::splineinitx{$label}=$x; - - my $y=&Apache::lonxml::get_param('inity',$parstack,$safeeval); - unless ($y) { $y=0; } - $Apache::functionplotresponse::splineinity{$label}=$y; - - my $sx=&Apache::lonxml::get_param('scalex',$parstack,$safeeval); - unless ($sx) { $sx=$order; } - $Apache::functionplotresponse::splinescalex{$label}=$sx; - - my $sy=&Apache::lonxml::get_param('scaley',$parstack,$safeeval); - unless ($sy) { $sy=2; } - $Apache::functionplotresponse::splinescaley{$label}=$sy; - return ''; + my $result=''; + if ($target eq 'web') { + my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval); + $Apache::functionplotresponse::counter++; + if ($label=~/\W/) { + &Apache::lonxml::warning(&mt('Spline labels should only contain alphanumeric characters.')); + } + $label=~s/\W//gs; + unless ($label) { $label='S'.$Apache::functionplotresponse::counter; } + if ($Apache::functionplotresponse::splineorder{$label}) { + &Apache::lonxml::error(&mt('Spline labels must be unique.')); + } + + my $order=&Apache::lonxml::get_param('order',$parstack,$safeeval); + if ($order<2) { $order=2; } + if ($order>8) { $order=8; } + $Apache::functionplotresponse::splineorder{$label}=$order; + + my $x=&Apache::lonxml::get_param('initx',$parstack,$safeeval); + unless ($x) { $x=0; } + $Apache::functionplotresponse::splineinitx{$label}=$x; + + my $y=&Apache::lonxml::get_param('inity',$parstack,$safeeval); + unless ($y) { $y=0; } + $Apache::functionplotresponse::splineinity{$label}=$y; + + my $sx=&Apache::lonxml::get_param('scalex',$parstack,$safeeval); + unless ($sx) { $sx=$order; } + $Apache::functionplotresponse::splinescalex{$label}=$sx; + + my $sy=&Apache::lonxml::get_param('scaley',$parstack,$safeeval); + unless ($sy) { $sy=2; } + $Apache::functionplotresponse::splinescaley{$label}=$sy; + } elsif ($target eq 'edit') { + $result=&Apache::edit::tag_start($target,$token,'Spline'). + &Apache::edit::text_arg('Label:','label', + $token,'4').' '. + &Apache::edit::select_arg('Order:','order', + ['2','3','4','5','6','7','8','9'],$token).' '. + &Apache::edit::text_arg('Initial x-value:','initx', + $token,'4').' '. + &Apache::edit::text_arg('Initial y-value:','inity', + $token,'4').' '. + &Apache::edit::text_arg('Scale x:','scalex', + $token,'4').' '. + &Apache::edit::text_arg('Scale y:','scaley', + $token,'4'). + &Apache::edit::end_row(); + } elsif ($target eq 'modified') { + my $constructtag=&Apache::edit::get_new_args($token,$parstack, + $safeeval,'label','order','initx','inity', + 'scalex','scaley'); + if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); } + } + return $result; } sub end_spline { - return ''; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result=''; + if ($target eq 'edit') { + $result=&Apache::edit::end_table(); + } + return $result; } sub end_init_script { @@ -356,6 +468,40 @@ sub get_answer_from_form_fields { return ($answer,%coords); } +# +# The following functions calculate the cubic-hermite splines server-side +# + +sub cubic_hermite { + my ($t,$p1,$s1,$p2,$s2)=@_; + return (2.*$t*$t*$t-3.*$t*$t+1.)*$p1 + 5.*($t*$t*$t-2.*$t*$t+$t)*($s1-$p1)+ + (-2.*$t*$t*$t+3.*$t*$t) *$p2 + 5.*($t*$t*$t-$t*$t) *($s2-$p2); +} + +# +# d/dt(...) +# + +sub ddt_cubic_hermite { + my ($t,$p1,$s1,$p2,$s2)=@_; + return (6.*$t*$t-6.*$t) *$p1 + 5.*(3.*$t*$t-4.*$t+1.)*($s1-$p1)+ + (-6.*$t*$t+6.*$t)*$p2 + 5.*(3.*$t*$t-2.*$t) *($s2-$p2); +} + +# +# d^2/dt^2(...) +# + +sub d2dt2_cubic_hermite { + my ($t,$p1,$s1,$p2,$s2)=@_; + return (12.*$t-6.) *$p1 + 5.*(6.*$t-4.)*($s1-$p1)+ + (-12.*$t+6.)*$p2 + 5.*(6.*$t-2.)*($s2-$p2); +} + +# +# Implentation of +# + sub start_functionplotresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; @@ -389,16 +535,53 @@ sub start_functionplotresponse { my $xaxisvisible=(&Apache::lonxml::get_param('xaxisvisible',$parstack,$safeeval)=~/on|true|yes|1/i?'true':'false'); my $yaxisvisible=(&Apache::lonxml::get_param('yaxisvisible',$parstack,$safeeval)=~/on|true|yes|1/i?'true':'false'); my $gridvisible=(&Apache::lonxml::get_param('gridvisible',$parstack,$safeeval)=~/on|true|yes|1/i?'true':'false'); + my $xlabel=&Apache::lonxml::get_param('xlabel',$parstack,$safeeval); + my $ylabel=&Apache::lonxml::get_param('ylabel',$parstack,$safeeval); + if ($target eq 'edit') { + $result.=&Apache::edit::start_table($token) + .''.&mt('Function Plot Question').'' + .''.&mt('Delete?').' ' + .&Apache::edit::deletelist($target,$token) + .'' + ." " + .&Apache::edit::end_row() + .&Apache::edit::start_spanning_row() + ."\n"; + $result.=&Apache::edit::text_arg('Label x-axis:','xlabel', + $token,'6').' '. + &Apache::edit::text_arg('Minimum x-value:','xmin', + $token,'4').' '. + &Apache::edit::text_arg('Maximum x-value:','xmax', + $token,'4').' '. + &Apache::edit::select_arg('x-axis visible:','xaxisvisible', + ['yes','no'],$token).'  '. + &Apache::edit::text_arg('Label y-axis:','ylabel', + $token,'6').' '. + &Apache::edit::text_arg('Minimum y-value:','ymin', + $token,'4').' '. + &Apache::edit::text_arg('Maximum y-value:','ymax', + $token,'4').' '. + &Apache::edit::select_arg('y-axis visible:','yaxisvisible', + ['yes','no'],$token).'  '. + &Apache::edit::select_arg('Grid visible:','gridvisible', + ['yes','no'],$token). + &Apache::edit::end_row().&Apache::edit::start_spanning_row(); + } elsif ($target eq 'modified') { + my $constructtag=&Apache::edit::get_new_args($token,$parstack, + $safeeval,'xlabel','xmin','xmax','ylabel','ymin','ymax', + 'xaxisvisible','yaxisvisible','gridvisible'); + if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } - if ($target eq 'meta') { + } elsif ($target eq 'meta') { $result=&Apache::response::meta_package_write('functionplotresponse'); - } elsif ($target eq 'web') { + } elsif ($target eq 'web') { # paste in the update routine to receive stuff back from the applet $result.=&update_script($internalid); # start the initscript for this applet $result.=&start_init_script($internalid); # put the axis commands inside $result.=&axes_script($internalid,$xmin,$xmax,$ymin,$ymax,$xaxisvisible,$yaxisvisible,$gridvisible); + $result.=&axes_label($internalid,$xlabel,$ylabel); # init script is left open } return $result; @@ -413,7 +596,7 @@ sub end_functionplotresponse { my $partid=$Apache::inputtags::part; my $internalid = $partid.'_'.$id; -# if ($target eq 'edit') { $result=&Apache::edit::end_table(); } + if ($target eq 'edit') { $result=&Apache::edit::end_table(); } if ($target eq 'grade' && &Apache::response::submitted() && $Apache::lonhomework::type eq 'exam') { @@ -425,8 +608,16 @@ sub end_functionplotresponse { && $Apache::lonhomework::type ne 'exam') { my ($response,%coords)=&get_answer_from_form_fields($internalid); $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; - $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}='INCORRECT'; - + my %previous=&Apache::response::check_for_previous($response,$partid,$id); +# +# Actually grade +# + my $ad='INCORRECT'; +# +# Store grading info +# + $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; + &Apache::response::handle_previous(\%previous,$ad); } elsif ($target eq 'web') { # Now is the time to render all of the stored splines foreach my $label (keys(%Apache::functionplotresponse::splineorder)) {