# LearningOnline Network with CAPA # option list style responses # # $Id: functionplotresponse.pm,v 1.37 2010/11/13 03:22:58 www Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # package Apache::functionplotresponse; use strict; use Apache::response(); use Apache::lonlocal; use Apache::lonnet; BEGIN { &Apache::lonxml::register('Apache::functionplotresponse',('functionplotresponse','backgroundplot','spline', 'functionplotrule','functionplotruleset', 'functionplotelements')); } # # There can be a number of applets on a page, each called ggbApplet_$id, # where $id is the "_"-concatenated part and responseid # sub geogebra_startcode { my ($id)=@_; return (< ENDSTARTCODE } sub geogebra_endcode { return &Apache::lonhtmlcommon::java_not_enabled()."\n"; } # # This is the internal GeoGebra bytecode which defines the spline functions # sub geogebra_spline_program { return (< ENDSPLINEPROGRAM } # # The standard set of parameters inside # sub geogebra_default_parameters { my ($id)=@_; return(< ENDDEFAULTPARAMETERS } # # This subroutine is called by LON-CAPA at # Each applet on the page will call function ggbOnInit when it is done loading # This function in turn will call the respective function registered by start_init_script # Which one of the registered functions is called is determined by ggbOnInitParam, which GeoGebra passes to ggbOnInit # sub init_script { 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) }"; my $calls=join("\n",map { "ggbInit_$_();" } (@Apache::functionplotresponse::callscripts)); return (< // ENDGGBINIT } } # # Each Geogebra applet is supposed to call this when parameters change # Changes the hidden fields on the web page # sub update_script { my ($id)=@_; return (< // ENDUPDATESCRIPT } # # Register the above update-handler for a variable # sub update_register { my ($id,$variable)=@_; return "document.ggbApplet_$id.registerObjectUpdateListener('$variable','updatePointCoordinates_$id');\n"; } # # Set a coordinate variable # sub set_coordinate { my ($id,$variable,$x,$y)=@_; return (<\n". "\n"; } # # Initialize a new coordinate variable at set a listener on it # sub new_coordinate { my ($id,$variable,$x,$y)=@_; if (defined($Apache::functionplotresponse::previous{&field_name($id,$variable,'x')})) { $x=$Apache::functionplotresponse::previous{&field_name($id,$variable,'x')}; } 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); return &set_coordinate($id,$variable,$x,$y).&update_register($id,$variable); } # # This registers the init-function call for ggbOnInit, which LON-CAPA will place at # It then starts the right headers # sub start_init_script { my ($id)=@_; # 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_backgroundplot { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1]; my $function=&Apache::lonxml::get_param('function',$parstack,$safeeval); my $fixed=(&Apache::lonxml::get_param('fixed',$parstack,$safeeval)=~/on|true|yes|1/i?1:0); unless ($function) { $function="0"; } if ($target eq 'web') { $result.=&plot_script($internalid,$function,$fixed); } elsif ($target eq 'edit') { $result=&Apache::edit::tag_start($target,$token,'Background Function Plot'). &Apache::edit::text_arg('Function:','function', $token,'16'). &Apache::edit::select_arg('Fixed location:','fixed', ['yes','no'],$token). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'function','fixed'); if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); } } return $result; } sub end_backgroundplot { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } # # # sub start_functionplotrule { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; my $label=&Apache::lonxml::get_param('index',$parstack,$safeeval); $Apache::functionplotresponse::counter++; if ($label=~/\W/) { &Apache::lonxml::warning(&mt('Rule indices should only contain alphanumeric characters.')); } $label=~s/\W//gs; unless ($label) { $label='R'.$Apache::functionplotresponse::counter; } else { $label='R'.$label; } if ($Apache::functionplotresponse::splineorder{$label}) { &Apache::lonxml::error(&mt('Rule indices must be unique.')); } if ($target eq 'grade') { # Simply remember - in order - for later my $beginninglabel=&Apache::lonxml::get_param('xinitiallabel',$parstack,$safeeval); my $endinglabel=&Apache::lonxml::get_param('xfinallabel',$parstack,$safeeval); if (($beginninglabel=~/\W/) || ($endinglabel=~/W/)) { &Apache::lonxml::warning(&mt('Rule labels must be alphanumeric.')); } $beginninglabel=~s/\W//gs; $endinglabel=~s/\W//gs; my $relationship=&Apache::lonxml::get_param('relationship',$parstack,$safeeval); $relationship=~s/\W//gs; $relationship=lc($relationship); unless ($relationship=~/^(eq|ge|gt|le|lt|ne)$/) { &Apache::lonxml::warning(&mt('Rule relationship not defined.')); $relationship='eq'; } my $derivative=&Apache::lonxml::get_param('derivativeorder',$parstack,$safeeval); unless (($derivative==0) || ($derivative==1) || ($derivative==2)) { &Apache::lonxml::warning(&mt('Rule derivative not defined.')); $derivative=0; } push(@Apache::functionplotresponse::functionplotrules,join(':',( $label, $derivative, &Apache::lonxml::get_param('xinitial',$parstack,$safeeval), $beginninglabel, &Apache::lonxml::get_param('xfinal',$parstack,$safeeval), $endinglabel, &Apache::lonxml::get_param('minimumlength',$parstack,$safeeval), &Apache::lonxml::get_param('maximumlength',$parstack,$safeeval), $relationship, &Apache::lonxml::get_param('value',$parstack,$safeeval), &Apache::lonxml::get_param('percenterror',$parstack,$safeeval) ))); } elsif ($target eq 'edit') { $result=&Apache::edit::tag_start($target,$token,'Function Plot Evaluation Rule'). &Apache::edit::text_arg('Index/Name:','index', $token,'10').' '. &Apache::edit::select_arg(&mt('Function:'),'derivativeorder', [['0','Function itself'], ['1','First derivative'], ['2','Second derivative']],$token).'
'. &Apache::edit::text_arg('(Initial) x-value:','xinitial', $token,'8'). &Apache::edit::select_or_text_arg('(Initial) x-value label:','xinitiallabel', [['start','Start of Plot']],$token,'8').'
'. &Apache::edit::text_arg('Optional final x-value for ranges:','xfinal', $token,'8'). &Apache::edit::select_or_text_arg('Optional final x-value label:','xfinallabel', [['end','End of Plot']],$token,'8').'
'. &Apache::edit::text_arg('Optional minimum length for range:','minimumlength', $token,'8'). &Apache::edit::text_arg('Optional maximum length for range:','maximumlength', $token,'8').'
'. &Apache::edit::select_arg(&mt('Relationship:'),'relationship', [['eq','equal'], ['ne','not equal'], ['ge','greater than or equal'], ['gt','greater than'], ['lt','less than'], ['le','less than or equal']],$token). $result.= &Apache::edit::select_or_text_arg('Value:','value', [['undef','not defined']],$token,'8'). &Apache::edit::text_arg('Percent error:','percenterror', $token,'8'). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'index','derivativeorder', 'xinitial','xinitiallabel','xfinal','xfinallabel', 'minimumlength','maximumlength', 'relationship','value','percenterror'); if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); } } return $result; } sub end_functionplotrule { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } # # # # Unfortunately, GeoGebra seems to want all splines after everything else, so we need to store them # sub start_spline { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; if ($target eq 'web') { my $label=&Apache::lonxml::get_param('index',$parstack,$safeeval); $Apache::functionplotresponse::counter++; if ($label=~/\W/) { &Apache::lonxml::warning(&mt('Spline indices should only contain alphanumeric characters.')); } $label=~s/\W//gs; unless ($label) { $label='S'.$Apache::functionplotresponse::counter; } else { $label='S'.$label; } if ($Apache::functionplotresponse::splineorder{$label}) { &Apache::lonxml::error(&mt('Spline indices 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('Index:','index', $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,'index','order','initx','inity', 'scalex','scaley'); if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); } } return $result; } sub end_spline { 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 { return (< ENDENDINIT } # # Storing and restoring spline coordinates from part answers # sub decode_previous_answer { my ($answer)=@_; foreach my $coordinate (split(/\,/,$answer)) { my ($key,$value)=split(/\=/,$coordinate); $Apache::functionplotresponse::previous{$key}=$value; } } sub get_answer_from_form_fields { my ($id)=@_; my $answer=''; my %coords=(); foreach my $field (keys(%env)) { if ($field=~/^form\.HWVAL\_$id/) { $field=~/^form\.(.*)$/; $coords{$1}=$env{$field}; } } $answer=join(',',map { $_.'='.$coords{$_} } (sort(keys(%coords)))); 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); } # # Array index calculation # sub array_index { my ($xmin,$xmax,$x)=@_; return int(($x-$xmin)/($xmax-$xmin)*400.+0.5); } # # Populate the arrays # sub populate_arrays { my ($id,$xmin,$xmax)=@_; for (my $i=0; $i<=400; $i++) { $Apache::functionplotresponse::actualxval[$i]=undef; $Apache::functionplotresponse::func[$i]=undef; $Apache::functionplotresponse::dfuncdx[$i]=undef; $Apache::functionplotresponse::d2funcd2x[$i]=undef; } unless ($xmax>$xmin) { return 'no_func'; } # Run over all splines in response foreach my $label (split(/\,/,$env{"form.HWVAL_AllSplines_$id"})) { my $xiold=-1; # Run over all points in spline for (my $i=1; $i<$env{"form.HWVAL_SplineOrder_".$id."_".$label}; $i++) { my $ni=$i+1; my @xparms=($env{'form.HWVAL_'.$id.'_'.$label.'P'.$i.'_x'}, $env{'form.HWVAL_'.$id.'_'.$label.'S'.$i.'_x'}, $env{'form.HWVAL_'.$id.'_'.$label.'P'.$ni.'_x'}, $env{'form.HWVAL_'.$id.'_'.$label.'S'.$ni.'_x'}); my @yparms=($env{'form.HWVAL_'.$id.'_'.$label.'P'.$i.'_y'}, $env{'form.HWVAL_'.$id.'_'.$label.'S'.$i.'_y'}, $env{'form.HWVAL_'.$id.'_'.$label.'P'.$ni.'_y'}, $env{'form.HWVAL_'.$id.'_'.$label.'S'.$ni.'_y'}); # Run in small steps over spline parameter for (my $t=0; $t<=1; $t+=0.0001) { my $xreal=&cubic_hermite($t,@xparms); my $xi=&array_index($xmin,$xmax,$xreal); if ($xi<$xiold) { return 'no_func'; } if (($xi>$xiold) && ($xi>=0) && ($xi<=400)) { if (defined($Apache::functionplotresponse::func[$xi])) { return 'no_func'; } $xiold=$xi; $Apache::functionplotresponse::actualxval[$xi]=$xreal; # Function value my $funcval=&cubic_hermite($t,@yparms); $Apache::functionplotresponse::func[$xi]=$funcval; if (defined($funcval)) { if ($xi<$Apache::functionplotresponse::functionplotrulelabels{'start'}) { $Apache::functionplotresponse::functionplotrulelabels{'start'}=$xi; } if ($xi>$Apache::functionplotresponse::functionplotrulelabels{'end'}) { $Apache::functionplotresponse::functionplotrulelabels{'end'}=$xi; } } # Chain rule # dy/dx=dy/dt/(dx/dt) my $dxdt=&ddt_cubic_hermite($t,@xparms); if ($dxdt) { $Apache::functionplotresponse::dfuncdx[$xi]=&ddt_cubic_hermite($t,@yparms)/$dxdt; # Second derivative $Apache::functionplotresponse::d2funcdx2[$xi]= ($dxdt*&d2dt2_cubic_hermite($t,@yparms)-&ddt_cubic_hermite($t,@yparms)*&d2dt2_cubic_hermite($t,@xparms))/ ($dxdt*$dxdt*$dxdt); } } } } } } # # Implementation of # sub start_functionplotresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; # To remember the splines - somehow, they need to come last undef %Apache::functionplotresponse::splineorder; undef %Apache::functionplotresponse::splineinitx; undef %Apache::functionplotresponse::splineinity; undef %Apache::functionplotresponse::splinescalex; undef %Apache::functionplotresponse::splinescaley; # Remember input fields, etc undef %Apache::functionplotresponse::previous; $Apache::functionplotresponse::inputfields=''; $Apache::functionplotresponse::counter=0; # Remember rules undef @Apache::functionplotresponse::functionplotrules; # Remember failed rules if ($target eq 'grade') { undef @Apache::functionplotresponse::failedrules; } # Delete previous awards undef $Apache::functionplotresponse::awarddetail; # Part and ID my $partid=$Apache::inputtags::part; my $id=&Apache::response::start_response($parstack,$safeeval); # Internal ID to mark the applet and its coordinates my $internalid = $partid.'_'.$id; # Previous answer &decode_previous_answer($Apache::lonhomework::history{"resource.$partid.$id.submission"}); # Parameters of my $xmin=&Apache::lonxml::get_param('xmin',$parstack,$safeeval); $xmin=(defined($xmin)?$xmin:-10); my $xmax=&Apache::lonxml::get_param('xmax',$parstack,$safeeval); $xmax=(defined($xmax)?$xmax:10); my $ymin=&Apache::lonxml::get_param('ymin',$parstack,$safeeval); $ymin=(defined($ymin)?$ymin:-10); my $ymax=&Apache::lonxml::get_param('ymax',$parstack,$safeeval); $ymax=(defined($ymax)?$ymax:10); if ($xmax<=$xmin) { &Apache::lonxml::warning('Maximum x-value needs to be larger than minimum value.'); $xmax=$xmin+20; } if ($ymax<=$ymin) { &Apache::lonxml::warning('Maximum y-value needs to be larger than minimum value.'); $ymax=$ymin+20; } 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::insertlist($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); } } elsif ($target eq 'meta') { $result=&Apache::response::meta_package_write('functionplotresponse'); } elsif (($target eq 'answer') && ($env{'form.answer_output_mode'} ne 'tex') && ($Apache::lonhomework::viewgrades == 'F')) { my (undef,undef,$udom,$uname)=&Apache::lonnet::whichuser(); my $windowopen=&Apache::lonhtmlcommon::javascript_docopen(); my $start_page = &Apache::loncommon::start_page('Rules Log', undef, {'only_body' => 1, 'bgcolor' => '#FFFFFF', 'js_ready' => 1,}); my $end_page = &Apache::loncommon::end_page({'js_ready' => 1,}); $uname =~s/\W//g; $udom =~s/\W//g; my $function_name = join('_','LONCAPA_scriptvars',$uname,$udom, $env{'form.counter'},$Apache::lonxml::curdepth); my $rules_var ="".&mt('Rules Log')."
"; &Apache::lonxml::add_script_result($rules_var); } return $result; } sub compare_rel { my ($relationship,$value,$realval,$tol)=@_; # is the real value undefined? unless (defined($realval)) { # the real value is not defined if ($relationship eq 'eq') { if ($value eq 'undef') { return 1; } else { return 0; } } elsif ($relationship eq 'ne') { if ($value eq 'undef') { return 0; } else { return 1; } } else { return 0; } } # is the expected value undefined? if ($value eq 'undef') { # but by now we know that the real value is defined return 0; } # both are defined. if ($relationship eq 'gt') { return ($realval>$value); } elsif ($relationship eq 'ge') { return ($realval>$value-$tol); } elsif ($relationship eq 'lt') { return ($realval<$value); } elsif ($relationship eq 'le') { return ($realval<$value+$tol); } elsif ($relationship eq 'ne') { return (abs($value-$realval)>$tol); } else { return (abs($value-$realval)<$tol); } return 0; } sub addlog { my ($text)=@_; $Apache::functionplotresponse::ruleslog.=$text.'
'; } sub actualval { my ($i,$xmin,$xmax)=@_; return $xmin+$i/400.*($xmax-$xmin); } sub functionplotrulecheck { my ($rule,$xmin,$xmax,$ymin,$ymax)=@_; my ($label,$derivative,$xinitial,$xinitiallabel,$xfinal,$xfinallabel,$minimumlength,$maximumlength,$relationship,$value,$percent) =split(/\:/,$rule); $percent=($percent>0?$percent:5); &addlog("================="); &addlog("Rule $label for ".('function itself','first derivative','second derivative')[$derivative]." $relationship $value"); my $li=0; my $lh=400; # Special case: the upper boundary was not defined # and needs to be set to the value where # the condition is not true anymore => set flag my $findupper=0; if (($xfinal eq '') && (!defined($Apache::functionplotresponse::functionplotrulelabels{$xfinallabel})) && ($xfinallabel)) { $findupper=1; } # if a hard value is set for the boundaries, it overrides the label if (($xinitial ne '') && ($xinitiallabel ne '') && ($xinitiallabel ne 'start')) { $li=&array_index($xmin,$xmax,$xinitial); $Apache::functionplotresponse::functionplotrulelabels{$xinitiallabel}=$li; } if (($xfinal ne '') && ($xfinallabel ne '') && ($xfinallabel ne 'end')) { $lh=&array_index($xmin,$xmax,$xfinal); $Apache::functionplotresponse::functionplotrulelabels{$xfinallabel}=$lh; } # if the label is defined, use it if (defined($Apache::functionplotresponse::functionplotrulelabels{$xinitiallabel})) { &addlog("Using lower label $xinitiallabel"); $li=$Apache::functionplotresponse::functionplotrulelabels{$xinitiallabel}; } else { $li=&array_index($xmin,$xmax,$xinitial); } unless ($findupper) { if (defined($Apache::functionplotresponse::functionplotrulelabels{$xfinallabel})) { &addlog("Using upper label $xfinallabel"); $lh=$Apache::functionplotresponse::functionplotrulelabels{$xfinallabel}-1; } else { $lh=&array_index($xmin,$xmax,$xfinal); } } # Basic sanity checks if ($li<0) { $li=0; } if ($lh>400) { $lh=400; } if ($li>$lh) { $lh=$li; } &addlog("Boundaries: x=".&actualval($li,$xmin,$xmax)." (".$Apache::functionplotresponse::actualxval[$li]."; index $li)) to x=". &actualval($lh,$xmin,$xmax)." (".$Apache::functionplotresponse::actualxval[$lh]."; index $lh))"); if ($findupper) { &addlog("Looking for label $xfinallabel"); } my $tol=$percent*($ymax-$ymin)/100; if ($xmax>$xmin) { if ($derivative==2) { $tol=4.*$tol/($xmax-$xmin); } elsif ($derivative==1) { $tol=2.*$tol/($xmax-$xmin); } } for (my $i=$li; $i<=$lh; $i++) { my $val; if ($derivative==2) { $val=$Apache::functionplotresponse::d2funcdx2[$i]; } elsif ($derivative==1) { $val=$Apache::functionplotresponse::dfuncdx[$i]; } else { $val=$Apache::functionplotresponse::func[$i]; } unless (&compare_rel($relationship,$value,$val,$tol)) { &addlog("Actual value ".(defined($val)?$val:'undef').", expected $value, tolerance $tol"); &addlog("Condition not fulfilled at x=".&actualval($i,$xmin,$xmax)." (".$Apache::functionplotresponse::actualxval[$i]."; index $i)"); if (($findupper) && ($i>$li)) { # check for minimum and maximum lengths my $length=&actualval($i,$xmin,$xmax)-&actualval($li,$xmin,$xmax); if ($minimumlength) { if ($length<$minimumlength) { &addlog("Rule $label failed, actual length $length, minimum length $minimumlength"); return 0; } } if ($maximumlength) { if ($length>$maximumlength) { &addlog("Rule $label failed, actual length $length, maximum length $maximumlength"); return 0; } } $Apache::functionplotresponse::functionplotrulelabels{$xfinallabel}=$i; &addlog("Rule $label passed, setting label $xfinallabel"); return 1; } else { &addlog("Rule $label failed."); my $hintlabel=$label; $hintlabel=~s/^R//; push(@Apache::functionplotresponse::failedrules,$hintlabel); &addlog("Set hint condition $hintlabel"); return 0; } } } &addlog("Rule $label passed."); return 1; } sub start_functionplotruleset { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; if ($target eq 'edit') { return &Apache::edit::start_table($token). ''.&mt('Function Plot Rule Set').'' .''.&mt('Delete?').' ' .&Apache::edit::deletelist($target,$token).'   '. &Apache::edit::insertlist($target,$token) .'' ." " .&Apache::edit::end_row() .&Apache::edit::start_spanning_row() ."\n"; } } sub end_functionplotruleset { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $id=$Apache::inputtags::response[-1]; my $partid=$Apache::inputtags::part; my $internalid = $partid.'_'.$id; if ($target eq 'edit' ) { return &Apache::edit::end_table(); } elsif ($target eq 'grade' && &Apache::response::submitted() && $Apache::lonhomework::type ne 'exam') { # # Actually grade # my $xmin=&Apache::lonxml::get_param('xmin',$parstack,$safeeval,-2); $xmin=(defined($xmin)?$xmin:-10); my $xmax=&Apache::lonxml::get_param('xmax',$parstack,$safeeval,-2); $xmax=(defined($xmax)?$xmax:10); my $ymin=&Apache::lonxml::get_param('ymin',$parstack,$safeeval,-2); $ymin=(defined($ymin)?$ymin:-10); my $ymax=&Apache::lonxml::get_param('ymax',$parstack,$safeeval,-2); $ymax=(defined($ymax)?$ymax:10); my $ad=''; undef %Apache::functionplotresponse::functionplotrulelabels; $Apache::functionplotresponse::ruleslog=''; $Apache::functionplotresponse::functionplotrulelabels{'start'}=400; $Apache::functionplotresponse::functionplotrulelabels{'end'}=0; if (&populate_arrays($internalid,$xmin,$xmax) eq 'no_func') { $ad='NOT_FUNCTION'; } else { &addlog("Start of function ".&actualval($Apache::functionplotresponse::functionplotrulelabels{'start'},$xmin,$xmax)." (index ". $Apache::functionplotresponse::functionplotrulelabels{'start'}.")"); &addlog("End of function ".&actualval($Apache::functionplotresponse::functionplotrulelabels{'end'},$xmin,$xmax)." (index ". $Apache::functionplotresponse::functionplotrulelabels{'end'}.")"); # We have a function that we can actually grade, go through the spline rules. foreach my $rule (@Apache::functionplotresponse::functionplotrules) { unless (&functionplotrulecheck($rule,$xmin,$xmax,$ymin,$ymax)) { $ad='INCORRECT'; last; } } # If it's not wrong, it's correct unless ($ad) { $ad='EXACT_ANS' }; } &addlog("Set hint conditions: ".join(",",@Apache::functionplotresponse::failedrules)); &addlog("Assigned award detail: $ad"); # Store for later to be assigned at end_functionplotresponse $Apache::functionplotresponse::awarddetail=$ad; } } sub end_functionplotresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; &Apache::response::end_response; my $result; my $id=$Apache::inputtags::response[-1]; my $partid=$Apache::inputtags::part; my $internalid = $partid.'_'.$id; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } if ($target eq 'grade' && &Apache::response::submitted() && $Apache::lonhomework::type eq 'exam') { &Apache::response::scored_response($partid,$id); } elsif ($target eq 'grade' && &Apache::response::submitted() && $Apache::lonhomework::type ne 'exam') { my ($response,%coords)=&get_answer_from_form_fields($internalid); $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; my %previous=&Apache::response::check_for_previous($response,$partid,$id); # # Assign grade # my $ad=$Apache::functionplotresponse::awarddetail; # # Store grading info # $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; &Apache::response::handle_previous(\%previous,$ad); } elsif ($target eq 'web') { undef @Apache::functionplotresponse::failedrules; } return $result; } sub end_functionplotelements { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result=''; my $id=$Apache::inputtags::response[-1]; my $partid=$Apache::inputtags::part; my $internalid = $partid.'_'.$id; if ($target eq 'edit' ) { $result=&Apache::edit::end_table(); } elsif ($target eq 'web') { # Now is the time to render all of the stored splines foreach my $label (keys(%Apache::functionplotresponse::splineorder)) { $result.=&generate_spline($internalid,$label); } # close the init script $result.=&end_init_script(); # register all splines in this response $result.=''."\n"; foreach my $label (keys(%Apache::functionplotresponse::splineorder)) { $result.=''."\n"; } # generate the input fields $result.=$Apache::functionplotresponse::inputfields; # actually start the -tag $result.=&geogebra_startcode($internalid); # load the spline bytecode $result.=&geogebra_spline_program(); # set default parameters $result.=&geogebra_default_parameters($internalid); # close the -tag $result.=&geogebra_endcode(); } return $result; } sub start_functionplotelements { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; my $id=$Apache::inputtags::response[-1]; my $partid=$Apache::inputtags::part; my $internalid = $partid.'_'.$id; if ($target eq 'edit') { return &Apache::edit::start_table($token). ''.&mt('Function Plot Elements').'' .''.&mt('Delete?').' ' .&Apache::edit::deletelist($target,$token).'   '. &Apache::edit::insertlist($target,$token) .'' ." " .&Apache::edit::end_row() .&Apache::edit::start_spanning_row() ."\n"; } elsif ($target eq 'web') { my $xmin=&Apache::lonxml::get_param('xmin',$parstack,$safeeval,-2); $xmin=(defined($xmin)?$xmin:-10); my $xmax=&Apache::lonxml::get_param('xmax',$parstack,$safeeval,-2); $xmax=(defined($xmax)?$xmax:10); my $ymin=&Apache::lonxml::get_param('ymin',$parstack,$safeeval,-2); $ymin=(defined($ymin)?$ymin:-10); my $ymax=&Apache::lonxml::get_param('ymax',$parstack,$safeeval,-2); $ymax=(defined($ymax)?$ymax:10); if ($xmax<=$xmin) { $xmax=$xmin+20; } if ($ymax<=$ymin) { $ymax=$ymin+20; } my $xaxisvisible=(&Apache::lonxml::get_param('xaxisvisible',$parstack,$safeeval,-2)=~/on|true|yes|1/i?'true':'false'); my $yaxisvisible=(&Apache::lonxml::get_param('yaxisvisible',$parstack,$safeeval,-2)=~/on|true|yes|1/i?'true':'false'); my $gridvisible=(&Apache::lonxml::get_param('gridvisible',$parstack,$safeeval,-2)=~/on|true|yes|1/i?'true':'false'); my $xlabel=&Apache::lonxml::get_param('xlabel',$parstack,$safeeval,-2); my $ylabel=&Apache::lonxml::get_param('ylabel',$parstack,$safeeval,-2); # 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; } 1; __END__ =head1 NAME Apache::functionplotresponse.pm; =head1 SYNOPSIS Handles tags associated with accepting function plots. This is part of the LearningOnline Network with CAPA project described at http://www.lon-capa.org. =head1 HANDLER SUBROUTINE start_functionplotresponse() =head1 OTHER SUBROUTINES =over =item end_functionplotresponse() =back =cut 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.