Diff for /loncom/homework/functionplotresponse.pm between versions 1.17 and 1.90

version 1.17, 2010/10/29 19:18:48 version 1.90, 2011/12/10 18:10:56
Line 1 Line 1
 # LearningOnline Network with CAPA  # LearningOnline Network with CAPA
 # option list style responses  # Functionplot responses
 #  #
 # $Id$  # $Id$
 #  #
Line 31  use strict; Line 31  use strict;
 use Apache::response();  use Apache::response();
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::lonnet;  use Apache::lonnet;
   use Apache::run;
   use LONCAPA;
    
 BEGIN {  BEGIN {
   &Apache::lonxml::register('Apache::functionplotresponse',('functionplotresponse','backgroundplot','spline','splinerule'));    &Apache::lonxml::register('Apache::functionplotresponse',('functionplotresponse','backgroundplot','spline',
                                                               'plotobject','plotvector',
                                                               'functionplotvectorrule','functionplotvectorsumrule',
                                                               'functionplotcustomrule',
                                                               'functionplotrule','functionplotruleset',
                                                               'functionplotelements'));
 }  }
   
 #  #
Line 42  BEGIN { Line 49  BEGIN {
 #  #
   
 sub geogebra_startcode {  sub geogebra_startcode {
     my ($id)=@_;      my ($id,$width,$height)=@_;
       $width=int(1.*$width);
       $height=int(1.*$height);
       unless ($width) { $width=700; }
       unless ($height) { $height=400; }
     return (<<ENDSTARTCODE);      return (<<ENDSTARTCODE);
 <applet name="ggbApplet_$id" code="geogebra.GeoGebraApplet" archive="geogebra.jar"  <applet name="ggbApplet_$id" code="geogebra.GeoGebraApplet" archive="geogebra.jar"
          codebase="/adm/geogebra/"  width="714" height="447" MAYSCRIPT>           codebase="/adm/geogebra/"  width="$width" height="$height" MAYSCRIPT>
        <param name="java_arguments" value="-Xmx512m -Djnlp.packEnabled=true"/>         <param name="java_arguments" value="-Xmx512m -Djnlp.packEnabled=true"/>
 ENDSTARTCODE  ENDSTARTCODE
 }  }
Line 59  sub geogebra_endcode { Line 70  sub geogebra_endcode {
 #  #
 sub geogebra_spline_program {  sub geogebra_spline_program {
     return (<<ENDSPLINEPROGRAM);      return (<<ENDSPLINEPROGRAM);
 <param name="ggbBase64" value="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"/>  <param name="ggbBase64" value="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"/>
 ENDSPLINEPROGRAM  ENDSPLINEPROGRAM
 }  }
   
Line 72  sub geogebra_default_parameters { Line 83  sub geogebra_default_parameters {
         <param name="image" value="/adm/lonIcons/lonanim.gif"  />          <param name="image" value="/adm/lonIcons/lonanim.gif"  />
         <param name="boxborder" value="false"  />          <param name="boxborder" value="false"  />
         <param name="centerimage" value="true"  />          <param name="centerimage" value="true"  />
         <param name="java_arguments" value="-Xmx512m" />   <param name="cache_archive" value="geogebra.jar, geogebra_main.jar, geogebra_gui.jar, geogebra_cas.jar, geogebra_export.jar, geogebra_algos.jar, geogebra_javascript.jar, geogebra_properties.jar, jlatexmath.jar, jlm_cyrillic.jar, jlm_greek.jar" />
         <param name="cache_archive" value="geogebra.jar, geogebra_main.jar, geogebra_gui.jar, geogebra_cas.jar, geogebra_export.jar, geogebra_properties.jar" />   <param name="cache_version" value="4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0,4.0.1.0" />
         <param name="cache_version" value="3.2.44.0, 3.2.44.0, 3.2.44.0, 3.2.44.0, 3.2.44.0, 3.2.44.0" />  
         <param name="framePossible" value="false" />          <param name="framePossible" value="false" />
   
         <param name="showResetIcon" value="false" />          <param name="showResetIcon" value="false" />
Line 107  sub init_script { Line 117  sub init_script {
           $script.="if (param=='applet_$id') { loaded_$id=true; }\n";            $script.="if (param=='applet_$id') { loaded_$id=true; }\n";
       }        }
       $script.="if (".join(' && ',map { "loaded_$_" } (@Apache::functionplotresponse::callscripts)).        $script.="if (".join(' && ',map { "loaded_$_" } (@Apache::functionplotresponse::callscripts)).
                ") { setTimeout('ggbInitAll()',20) }";                 ") { setTimeout('ggbInitAll()',200) }";
       my $calls=join("\n",map { "ggbInit_$_();" } (@Apache::functionplotresponse::callscripts));         my $calls=join("\n",map { "ggbInit_$_();" } (@Apache::functionplotresponse::callscripts)); 
       return (<<ENDGGBINIT);        return (<<ENDGGBINIT);
 <script type="text/javascript">  <script type="text/javascript">
Line 157  sub update_register { Line 167  sub update_register {
 }  }
   
 #  #
 # Set a coordinate variable  # Set a point coordinate variable
 #  #
 sub set_coordinate {  sub set_point_coordinate {
    my ($id,$variable,$x,$y)=@_;     my ($id,$variable,$x,$y,$fixed)=@_;
      my $mult=($fixed?'a*':'');
   # Get rid of wild exponents, make sure it's a number
      $x=1.*$x;
      $y=1.*$y;
   # GeoGebra does not understand "E"
      $x=~s/[e|E]/\*10\^/;
      $x=~s/\+//;
      $y=~s/[e|E]/\*10\^/;
      $y=~s/\+//;
    return (<<ENDSETVARIABLE);     return (<<ENDSETVARIABLE);
 document.ggbApplet_$id.evalCommand("$variable=($x,$y)");  document.ggbApplet_$id.evalCommand("a=1");
   document.ggbApplet_$id.evalCommand("$variable=$mult($x,$y)");
   document.ggbApplet_$id.setLabelVisible("$variable",false);
 ENDSETVARIABLE  ENDSETVARIABLE
 }  }
   
 #  #
   # Set a slope coordinate variable
   #
   sub set_slope_coordinate {
      my ($id,$variable,$xrel,$yrel,$xmin,$xmax,$ymin,$ymax,$pointname,$fixed)=@_;
      my $xvariable=$variable.'x';
      my $yvariable=$variable.'y';
      my $domain=$xmax-$xmin;
      my $range=$ymax-$ymin;
      my $xinterval=$domain/100.;
      my $yinterval=$range/200.;
      my $mult=($fixed?'a*':'');
      return (<<ENDSETSVARIABLE);
   document.ggbApplet_$id.evalCommand("a=1");
   document.ggbApplet_$id.evalCommand("$xvariable=Slider[$xinterval,$domain,$xinterval]");
   document.ggbApplet_$id.setVisible("$xvariable", false);
   document.ggbApplet_$id.evalCommand("$xvariable=$xrel");
   document.ggbApplet_$id.evalCommand("$yvariable=Slider[-$range,$range,$yinterval]");
   document.ggbApplet_$id.setVisible("$yvariable", false);
   document.ggbApplet_$id.evalCommand("$yvariable=$yrel");
   document.ggbApplet_$id.evalCommand("$variable=$mult($xvariable+x($pointname),$yvariable+y($pointname))");
   document.ggbApplet_$id.setLabelVisible("$variable", false);
   ENDSETSVARIABLE
   }
   
   #
 # Input field name for a coordinate variable  # Input field name for a coordinate variable
 #  #
   
Line 187  sub generate_input_field { Line 233  sub generate_input_field {
 }  }
   
 #  #
 # Initialize a new coordinate variable at set a listener on it  # Initialize a new point coordinate variable at set a listener on it
   #
   sub new_point_coordinate {
       my ($id,$variable,$x,$y,$fixed)=@_;
       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_point_coordinate($id,$variable,$x,$y,$fixed).&update_register($id,$variable);
   }
   
   #
   # Initialize a new slope coordinate variable at set a listener on it
   #
   sub new_slope_coordinate {
       my ($id,$variable,$x,$y,$pointname,$xp,$yp,$xmin,$xmax,$ymin,$ymax,$fixed)=@_;
   #
   # $variable: name of the slope point
   # $x, $y: coordinates of the slope point
   # $pointname: name of the associated point point
   # $xp $yp: coordinates of the point point
 #  #
 sub new_coordinate {  
     my ($id,$variable,$x,$y)=@_;  
     if (defined($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')};         $x=$Apache::functionplotresponse::previous{&field_name($id,$variable,'x')};
     }      }
     if (defined($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')};         $y=$Apache::functionplotresponse::previous{&field_name($id,$variable,'y')};
     }      }
       if (defined($Apache::functionplotresponse::previous{&field_name($id,$pointname,'x')})) {
          $xp=$Apache::functionplotresponse::previous{&field_name($id,$pointname,'x')};
       }
       if (defined($Apache::functionplotresponse::previous{&field_name($id,$pointname,'y')})) {
          $yp=$Apache::functionplotresponse::previous{&field_name($id,$pointname,'y')};
       }
   
     &generate_input_field($id,$variable,$x,$y);      &generate_input_field($id,$variable,$x,$y);
     return &set_coordinate($id,$variable,$x,$y).&update_register($id,$variable);      my $xrel=$x-$xp;
       my $yrel=$y-$yp;
       return &set_slope_coordinate($id,$variable,$xrel,$yrel,$xmin,$xmax,$ymin,$ymax,$pointname,$fixed).&update_register($id,$variable);
 }  }
   
 #  #
Line 240  ENDAXESSCRIPT Line 316  ENDAXESSCRIPT
 }  }
   
 sub axes_label {  sub axes_label {
     my ($id,$xlabel,$ylabel)=@_;      my ($id,$xmin,$xmax,$ymin,$ymax,$xlabel,$ylabel)=@_;
     unless ($xlabel || $ylabel) { return ''; }      unless ($xlabel || $ylabel) { return ''; }
     my $return='document.ggbApplet_'.$id.'.evalCommand("topRight=Corner[3]");';      my $return='document.ggbApplet_'.$id.'.evalCommand("topRight=Corner[3]");';
     if ($xlabel) {      if ($xlabel) {
         if (($ymin<0) && ($ymax>0)) {
        $return.=(<<ENDXAXISLABELSCRIPT);         $return.=(<<ENDXAXISLABELSCRIPT);
 document.ggbApplet_$id.evalCommand("Xlabel=(x(topRight)-AxisStepX[],AxisStepY[]/6)");  document.ggbApplet_$id.evalCommand("Xlabel=(x(topRight)-AxisStepX[],AxisStepY[]/6)");
 document.ggbApplet_$id.setVisible("Xlabel",false);  document.ggbApplet_$id.setVisible("Xlabel",false);
 document.ggbApplet_$id.evalCommand("Text[\\"$xlabel\\", Xlabel]");  document.ggbApplet_$id.evalCommand("Text[\\"$xlabel\\", Xlabel]");
 ENDXAXISLABELSCRIPT  ENDXAXISLABELSCRIPT
         } else {
          $return.=(<<ENDXOFFAXISLABEL);
   document.ggbApplet_$id.evalCommand("LowerRight=Corner[2]");
   document.ggbApplet_$id.evalCommand("Text[\\"$xlabel\\", (x(LowerRight) - AxisStepX[], y(LowerRight) + AxisStepY[] / 2)]");
   ENDXOFFAXISLABEL
         }
     }      }
     if ($ylabel) {      if ($ylabel) {
         if (($xmin<0) && ($xmax>0)) {
        $return.=(<<ENDYAXISLABELSCRIPT);         $return.=(<<ENDYAXISLABELSCRIPT);
 document.ggbApplet_$id.evalCommand("Ylabel=(AxisStepX[]/6,y(topRight)-AxisStepY[]/3)");  document.ggbApplet_$id.evalCommand("Ylabel=(AxisStepX[]/6,y(topRight)-AxisStepY[]/3)");
 document.ggbApplet_$id.setVisible("Ylabel",false);  document.ggbApplet_$id.setVisible("Ylabel",false);
 document.ggbApplet_$id.evalCommand("Text[\\"$ylabel\\", Ylabel]");  document.ggbApplet_$id.evalCommand("Text[\\"$ylabel\\", Ylabel]");
 ENDYAXISLABELSCRIPT  ENDYAXISLABELSCRIPT
         } else {
          $return.=(<<ENDYOFFAXISLABEL);
   document.ggbApplet_$id.evalCommand("UpperLeft=Corner[4]");
   document.ggbApplet_$id.evalCommand("Text[\\"$ylabel\\", (x(UpperLeft) + AxisStepX[] / 5, y(UpperLeft) - AxisStepY[] / 1.8)]");
   ENDYOFFAXISLABEL
         }
     }      }
     return $return;      return $return;
 }  }
   
   #
   # Subroutine to produce background and answer plots
   #
   
 sub plot_script {  sub plot_script {
    my ($id,$function,$fixed)=@_;     my ($id,$function,$fixed,$label,$color,$xmin,$xmax,$thickness)=@_;
      $label=~s/\W//g;
      if (($label) && ($label!~/^[A-Za-z]/)) {
         $label='C'.$label;
      }
      my $visible=0;
      if ($label) {
         $visible="1";
      } else {
         $Apache::functionplotresponse::counter++;
         $label='C'.$Apache::functionplotresponse::counter;
      }
      my $rc=0;
      my $gc=0;
      my $bc=0;
      if ($color) {
         my ($rh,$gh,$bh)=($color=~/(..)(..)(..)/);
         $rc=hex($rh);
         $gc=hex($gh);
         $bc=hex($bh);
      }
    if ($fixed) {     if ($fixed) {
 # Use stupid trick to nail this to a location        return "document.ggbApplet_$id.evalCommand('$label=Function[$function,$xmin,$xmax]');\n".
 # Oddly, it seems like only one plot cannot be nailed to a location               ($visible?'':"document.ggbApplet_$id.setLabelVisible('$label', false);\n").
 # Non-nailed-down plots apparently get overwritten               ($color?"document.ggbApplet_$id.setColor('$label',$rc,$gc,$bc);\n":'').
       return (<<ENDPLOTSCRIPT);               ($thickness?"document.ggbApplet_$id.setLineThickness('$label',$thickness);\n":'');
             document.ggbApplet_$id.evalCommand("a=1");  
             document.ggbApplet_$id.setVisible("a",false);  
             // This MUST be a DEPENDENT OBJECT in order to be locked down:  
             document.ggbApplet_$id.evalCommand("y=a*($function)");  
 ENDPLOTSCRIPT  
    } else {     } else {
        return "document.ggbApplet_$id.evalCommand('y=$function')";         return "document.ggbApplet_$id.evalCommand('y=$function');\n";
      }
   }
   
   #
   # Subroutine to produce objects
   #
   
   sub plotobject_script {
      my ($id,$label,$x,$y)=@_;
      unless ($label) {
         $Apache::functionplotresponse::counter++;
         $label='O'.$Apache::functionplotresponse::counter;
      }
      &generate_input_field($id,$label,$x,$y);
      return "document.ggbApplet_$id.evalCommand('a=1');\n".
             "document.ggbApplet_$id.setVisible('a', false);\n".
             "document.ggbApplet_$id.setLabelVisible('a', false);\n".
             "document.ggbApplet_$id.evalCommand('$label=a*($x,$y)');\n".
             "document.ggbApplet_$id.setVisible('$label', true);\n".
             "document.ggbApplet_$id.setLabelVisible('$label', true);\n";
   }
   
   #
   # Subroutine to produce vectors
   #
   
   sub plotvector_script {
      my ($id,$label,$xs,$ys,$xe,$ye,$xmin,$xmax)=@_;
      unless ($label) {
         $Apache::functionplotresponse::counter++;
         $label='V'.$Apache::functionplotresponse::counter;
      }
      my $startlabel=$label.'Start';
      my $endlabel=$label.'End';
      my $pointlabel=$label.'Point';
      my $pointx=2.*($xmax-$xmin)+$xmax;
      my $anglelabel=$label.'Angle';
      return 
          &new_point_coordinate($id,$startlabel,$xs,$ys,0).
          &new_point_coordinate($id,$endlabel,$xe,$ye,0).
          (<<ENDVECTOR);
   document.ggbApplet_$id.evalCommand("$label=Vector[$startlabel,$endlabel]");
   document.ggbApplet_$id.setLabelVisible("$label",true);
   document.ggbApplet_$id.setLineThickness("$label",8);
   document.ggbApplet_$id.evalCommand("$pointlabel=($pointx,y($startlabel))");
   document.ggbApplet_$id.evalCommand("$anglelabel=Angle[$pointlabel,$startlabel,$endlabel]");
   document.ggbApplet_$id.setLabelVisible("$anglelabel",true);
   document.ggbApplet_$id.setLabelStyle("$anglelabel",VALUE=2);
   ENDVECTOR
   }
   
   #
   # Answer spline display
   # 
   # points: x,y,slope_x,slope_y
   
   sub answer_spline_script {
      my ($id,@points)=@_;
      my $order=int(($#points+1)/4);
      if ($order<2) { $order=2; }
      if ($order>8) { $order=8; }
      $Apache::functionplotresponse::counter++;
      my $label='CSpline'.$Apache::functionplotresponse::counter;
      my $output='document.ggbApplet_'.$id.'.evalCommand("'.$label.'=Spline'.$order.'[';
      for (my $i=0;$i<=$#points;$i+=4) {
         $output.="($points[$i],$points[$i+1]),($points[$i+2],$points[$i+3]),";
      }
      $output=~s/\,$//;
      $output.=']");'."\n";
      for (my $i=2; $i<2*$order; $i+=2) {
          $output.='document.ggbApplet_'.$id.'.setColor("'.$label.'_'.($i>=10?'{':'').$i.($i>=10?'}':'').'",0,170,0);'."\n";
      }
      for (my $i=1; $i<2*$order; $i+=2) {
          $output.='document.ggbApplet_'.$id.'.setVisible("'.$label.'_'.($i>=10?'{':'').$i.($i>=10?'}':'').'",false);'."\n";
    }     }
   
      return $output;
 }  }
   
 #  #
Line 282  ENDPLOTSCRIPT Line 467  ENDPLOTSCRIPT
 #  #
   
 sub generate_spline {  sub generate_spline {
    my ($id,$label)=@_;     my ($id,$label,$xmin,$xmax,$ymin,$ymax,$fixed)=@_;
    my $result='';     my $result='';
    my $order=$Apache::functionplotresponse::splineorder{$label};     my $order=$Apache::functionplotresponse::splineorder{$label};
    my $x=$Apache::functionplotresponse::splineinitx{$label};     my $x=$Apache::functionplotresponse::splineinitx{$label};
Line 291  sub generate_spline { Line 476  sub generate_spline {
    my $sy=$Apache::functionplotresponse::splinescaley{$label};     my $sy=$Apache::functionplotresponse::splinescaley{$label};
    my @coords=();     my @coords=();
    foreach my $i (1..$order) {     foreach my $i (1..$order) {
        $result.=&new_coordinate($id,$label.'P'.$i,$x,$y);         $result.=&new_point_coordinate($id,$label.'P'.$i,$x,$y,$fixed);
          my $xp=$x;
        $x+=$sx/(2.*($order-1));         $x+=$sx/(2.*($order-1));
        push(@coords,$label.'P'.$i);         push(@coords,$label.'P'.$i);
        $result.=&new_coordinate($id,$label.'S'.$i,$x,$y+$sy);         $result.=&new_slope_coordinate($id,$label.'S'.$i,$x,$y+$sy,$label.'P'.$i,$xp,$y,$xmin,$xmax,$ymin,$ymax,$fixed);
        $x+=$sx/(2.*($order-1));         $x+=$sx/(2.*($order-1));
        push(@coords,$label.'S'.$i);         push(@coords,$label.'S'.$i);
    }     }
    $result.='document.ggbApplet_'.$id.'.evalCommand("Spline'.$order.'['.join(',',@coords).']");'."\n";     $result.='document.ggbApplet_'.$id.'.evalCommand("Spline'.$order.'['.join(',',@coords).']");'."\n";
    return $result;     return $result;
 }  }
   
   #
   # Object
   #
   
   sub start_plotobject {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      my $result='';
      my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1];
      my $x=&Apache::lonxml::get_param('x',$parstack,$safeeval);
      my $y=&Apache::lonxml::get_param('y',$parstack,$safeeval);
      my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval);
      $label=~s/\W//gs;
      $label=ucfirst($label);
      unless ($label) { $label="NewObject"; }
      if ($target eq 'web') {
         my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-3);
         unless (defined($x)) { $x=$xmin; }
         unless (defined($y)) { $y=$ymin; }
         $result.=&plotobject_script($internalid,$label,$x,$y);
      } elsif ($target eq 'edit') {
           $result=&Apache::edit::tag_start($target,$token,'Plot Object').
                &Apache::edit::text_arg('Label on Plot:','label',
                                        $token,'16').
                &Apache::edit::text_arg('x:','x',
                                        $token,'8').
                &Apache::edit::text_arg('y:','y',
                                        $token,'8').
                &Apache::edit::end_row();
     } elsif ($target eq 'modified') {
       $env{'form.'.&Apache::edit::html_element_name('label')}=ucfirst($env{'form.'.&Apache::edit::html_element_name('label')});
       my $constructtag=&Apache::edit::get_new_args($token,$parstack,$safeeval,'label','x','y');
       if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
     }
     return $result;
   }
   
   sub end_plotobject {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      my $result='';
      if ($target eq 'edit') {
          $result=&Apache::edit::end_table();
      }
      return $result;
   }
   
   #
   # Vector
   #
   
   sub start_plotvector {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      my $result='';
      my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1];
      my $tailx=&Apache::lonxml::get_param('tailx',$parstack,$safeeval);
      my $taily=&Apache::lonxml::get_param('taily',$parstack,$safeeval);
      my $tipx=&Apache::lonxml::get_param('tipx',$parstack,$safeeval);
      my $tipy=&Apache::lonxml::get_param('tipy',$parstack,$safeeval);
   
      my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval);
      $label=~s/\W//gs;
      $label=ucfirst($label);
      unless ($label) { $label="NewVector"; }
      if ($target eq 'web') {
         my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-3);
         unless (defined($tailx)) { $tailx=$xmin; }
         unless (defined($taily)) { $taily=$ymin; }
         unless (defined($tipx)) { $tipx=$xmin; }
         unless (defined($tipy)) { $tipy=$ymin; }
         $result.=&plotvector_script($internalid,$label,$tailx,$taily,$tipx,$tipy,$xmin,$xmax);
      } elsif ($target eq 'edit') {
           $result=&Apache::edit::tag_start($target,$token,'Plot Vector').
                &Apache::edit::text_arg('Label on Plot:','label',
                                        $token,'16').
                &Apache::edit::text_arg('Tail x:','tailx',
                                        $token,'8').
                &Apache::edit::text_arg('Tail y:','taily',
                                        $token,'8').
                &Apache::edit::text_arg('Tip x:','tipx',
                                        $token,'8').
                &Apache::edit::text_arg('Tip y:','tipy',
                                        $token,'8').
   
                &Apache::edit::end_row();
     } elsif ($target eq 'modified') {
       $env{'form.'.&Apache::edit::html_element_name('label')}=ucfirst($env{'form.'.&Apache::edit::html_element_name('label')});
       my $constructtag=&Apache::edit::get_new_args($token,$parstack,$safeeval,'label','tailx','taily','tipx','tipy');
       if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
     }
     return $result;
   }
   
   sub end_plotvector {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      my $result='';
      if ($target eq 'edit') {
          $result=&Apache::edit::end_table();
      }
      return $result;
   }
   
   
   
 #  #
 # <backgroundplot function="..." fixed="yes/no" />  # <backgroundplot function="..." fixed="yes/no" />
 #  #
Line 309  sub start_backgroundplot { Line 598  sub start_backgroundplot {
    my $result='';     my $result='';
    my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1];     my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1];
    my $function=&Apache::lonxml::get_param('function',$parstack,$safeeval);     my $function=&Apache::lonxml::get_param('function',$parstack,$safeeval);
      my $xinitial=&Apache::lonxml::get_param('xinitial',$parstack,$safeeval);
      my $xfinal=&Apache::lonxml::get_param('xfinal',$parstack,$safeeval);
      my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval);
      my $color=&Apache::lonxml::get_param('color',$parstack,$safeeval);
      $color=~s/[^a-fA-F0-9]//gs;
      unless (length($color)==6) { $color=''; }
    my $fixed=(&Apache::lonxml::get_param('fixed',$parstack,$safeeval)=~/on|true|yes|1/i?1:0);     my $fixed=(&Apache::lonxml::get_param('fixed',$parstack,$safeeval)=~/on|true|yes|1/i?1:0);
     
    unless ($function) { $function="0"; }     unless ($function) { $function="0"; }
    if ($target eq 'web') {     if ($target eq 'web') {
       $result.=&plot_script($internalid,$function,$fixed);        my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-3);
         unless (defined($xinitial)) { $xinitial=$xmin; }
         unless (defined($xfinal)) { $xfinal=$xmax; }
         $result.=&plot_script($internalid,$function,$fixed,$label,$color,$xinitial,$xfinal);
    } elsif ($target eq 'edit') {     } elsif ($target eq 'edit') {
         $result=&Apache::edit::tag_start($target,$token,'Background Function Plot').          $result=&Apache::edit::tag_start($target,$token,'Background Function Plot').
              &Apache::edit::text_arg('Function:','function',               &Apache::edit::text_arg('Function:','function',
                                      $token,'16').                                       $token,'16').
                &Apache::edit::text_arg('Initial x-value (optional):','xinitial',
                                        $token,'8').
                &Apache::edit::text_arg('Final x-value (optional):','xfinal',
                                        $token,'8').
                &Apache::edit::text_arg('Label on Plot:','label',
                                        $token,'8').
                &Apache::edit::text_arg('Color (hex code):','color',
                                        $token,'8').
              &Apache::edit::select_arg('Fixed location:','fixed',               &Apache::edit::select_arg('Fixed location:','fixed',
                                   ['yes','no'],$token).                                    ['yes','no'],$token).
              &Apache::edit::end_row();               &Apache::edit::end_row();
   } elsif ($target eq 'modified') {    } elsif ($target eq 'modified') {
     my $constructtag=&Apache::edit::get_new_args($token,$parstack,      my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                                                  $safeeval,'function','fixed');                                                   $safeeval,'function','label','xinitial','xfinal','color','fixed');
     if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }      if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
   }    }
   return $result;    return $result;
Line 339  sub end_backgroundplot { Line 645  sub end_backgroundplot {
 }  }
   
 #  #
 # <splinerule ... />  # <functionplotrule ... />
 #  #
 sub start_splinerule {  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 ($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==-1) || ($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 Graph Rule').
                &Apache::edit::text_arg('Index/Name:','index',
                                        $token,'10').'&nbsp;'.
                &Apache::edit::select_arg(&mt('Function:'),'derivativeorder',
                                     [['0','Function itself'],
                                      ['1','First derivative'],
                                      ['2','Second derivative'],
                                      ['-1','Integral']],$token).'<br />'.
                &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'],
                                                   ['end','End of Plot']],$token,'8').'<br />'.
   
                &Apache::edit::text_arg('Final x-value (optional):','xfinal',
                                         $token,'8').
                &Apache::edit::select_or_text_arg('Final x-value label (optional):','xfinallabel',
                                                  [['end','End of Plot']],$token,'8').'<br />'.
                &Apache::edit::text_arg('Minimum length for range (optional):','minimumlength',
                                        $token,'8').
                &Apache::edit::text_arg('Maximum length for range (optional):','maximumlength',
                                        $token,'8').'<br />'.
                &Apache::edit::select_or_text_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,'30').
                &Apache::edit::text_arg('Percent error:','percenterror',
                                        $token,'8').
                &Apache::edit::end_row();
     } elsif ($target eq 'modified') {
       if (($env{'form.'.&Apache::edit::html_element_name('xinitial')} ne '') && ($env{'form.'.&Apache::edit::html_element_name('xinitiallabel')} eq 'start')) {
          $env{'form.'.&Apache::edit::html_element_name('xinitiallabel')}='';
       }
       if (($env{'form.'.&Apache::edit::html_element_name('xfinal')} ne '') && ($env{'form.'.&Apache::edit::html_element_name('xfinallabel')} eq 'end')) {
          $env{'form.'.&Apache::edit::html_element_name('xfinallabel')}='';
       }
       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;
   }
   
   
   #
   # <functionplotvectorrule ... />
   #
   sub start_functionplotvectorrule {
      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 ($target eq 'grade') {
   # Simply remember - in order - for later
   
         my $id=$Apache::inputtags::response[-1];
         my $partid=$Apache::inputtags::part;
         my $internalid = $partid.'_'.$id;
   
         my $vector=&Apache::lonxml::get_param('vector',$parstack,$safeeval);
         $vector=~s/\W//gs;
         $vector=ucfirst($vector);
   
         push(@Apache::functionplotresponse::functionplotvectorrules,join(':',(
              $label,
              'vector',
              $internalid,
              $vector,
              &Apache::lonxml::get_param('attachpoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('notattachpoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('tailpoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('tippoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('nottailpoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('nottippoint',$parstack,$safeeval),
              &Apache::lonxml::get_param('length',$parstack,$safeeval),
              &Apache::lonxml::get_param('angle',$parstack,$safeeval),
              &Apache::lonxml::get_param('lengtherror',$parstack,$safeeval),
              &Apache::lonxml::get_param('angleerror',$parstack,$safeeval),
             )));
      } elsif ($target eq 'edit') {
           $result=&Apache::edit::tag_start($target,$token,'Function Plot Vector Rule').
                &Apache::edit::text_arg('Index/Name:','index',
                                        $token,'10').'&nbsp;'.
                &Apache::edit::text_arg('Vector:','vector',
                                         $token,'16').'<br />'.
                &Apache::edit::text_arg('Attached to object:','attachpoint',
                                         $token,'16').
                &Apache::edit::text_arg('Not attached to object:','notattachpoint',
                                         $token,'16').'<br />'.
                &Apache::edit::text_arg('Tail attached to object:','tailpoint',
                                         $token,'16').
                &Apache::edit::text_arg('Tip attached to object:','tippoint',
                                         $token,'16').
                &Apache::edit::text_arg('Tail not attached to object:','nottailpoint',
                                         $token,'16').
                &Apache::edit::text_arg('Tip not attached to object:','nottippoint',
                                         $token,'16').'<br />'.
                &Apache::edit::text_arg('Length:','length',
                                        $token,'30').
                &Apache::edit::text_arg('Absolute error length:','lengtherror',
                                        $token,'8').'<br />'.
                &Apache::edit::text_arg('Angle:','angle',
                                        $token,'30').
                &Apache::edit::text_arg('Absolute error angle:','angleerror',
                                        $token,'8').
                &Apache::edit::end_row();
     } elsif ($target eq 'modified') {
       $env{'form.'.&Apache::edit::html_element_name('vector')}=ucfirst($env{'form.'.&Apache::edit::html_element_name('vector')});
       my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                                                    $safeeval,'index','vector','attachpoint','notattachpoint',
                                                              'tailpoint','tippoint','nottailpoint','nottipoint',
                                                              'length','angle',
                                                              'lengtherror','angleerror');
       if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
      }
      return $result;
   }
   
   sub end_functionplotvectorrule {
    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
    my $result='';     my $result='';
    my $internalid = $Apache::inputtags::part.'_'.$Apache::inputtags::response[-1];  
    if ($target eq 'edit') {     if ($target eq 'edit') {
         $result=&Apache::edit::tag_start($target,$token,'Spline Evaluation Rule').         $result=&Apache::edit::end_table();
                 &Apache::edit::end_row();     }
      return $result;
   }
   
   #
   # <functionplotvectorsumrule ... />
   #
   sub start_functionplotvectorsumrule {
      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 ($target eq 'grade') {
   # Simply remember - in order - for later
         my $id=$Apache::inputtags::response[-1];
         my $partid=$Apache::inputtags::part;
         my $internalid = $partid.'_'.$id;
         my $vectors=&Apache::lonxml::get_param('vectors',$parstack,$safeeval);
         push(@Apache::functionplotresponse::functionplotvectorrules,join(':',(
              $label,
              'sum',
              $internalid,
              $vectors,
              &Apache::lonxml::get_param('length',$parstack,$safeeval),
              &Apache::lonxml::get_param('angle',$parstack,$safeeval),
              &Apache::lonxml::get_param('lengtherror',$parstack,$safeeval),
              &Apache::lonxml::get_param('angleerror',$parstack,$safeeval),
             )));
      } elsif ($target eq 'edit') {
           $result=&Apache::edit::tag_start($target,$token,'Function Plot Vector Sum Rule').
                &Apache::edit::text_arg('Index/Name:','index',
                                        $token,'10').'&nbsp;'.
                &Apache::edit::text_arg('Comma-separated list of vectors:','vectors',
                                         $token,'30').'<br />'.
                &Apache::edit::text_arg('Sum vector length:','length',
                                        $token,'30').
                &Apache::edit::text_arg('Absolute error length:','lengtherror',
                                        $token,'8').'<br />'.
                &Apache::edit::text_arg('Sum vector angle:','angle',
                                        $token,'30').
                &Apache::edit::text_arg('Absolute error angle:','angleerror',
                                        $token,'8').
                &Apache::edit::end_row();
      } elsif ($target eq 'modified') {
         my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                                                      $safeeval,'index','vectors',
                                                                'length','angle',
                                                                'lengtherror','angleerror');
         if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
    }     }
    return $result;     return $result;
 }  }
   
 sub end_splinerule {  sub end_functionplotvectorsumrule {
    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
    my $result='';     my $result='';
    if ($target eq 'edit') {     if ($target eq 'edit') {
Line 361  sub end_splinerule { Line 918  sub end_splinerule {
    return $result;     return $result;
 }  }
   
   #
   # <functionplotcustom ... />
   #
   sub start_functionplotcustomrule {
      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;
      }
      &Apache::lonxml::register('Apache::response',('answer'));
      if ($target eq 'edit') {
           $result=&Apache::edit::tag_start($target,$token,'Function Plot Custom Rule').
                &Apache::edit::text_arg('Index/Name:','index',$token,'10').
                &Apache::edit::end_row();
     } elsif ($target eq 'modified') {
         my $constructtag=&Apache::edit::get_new_args($token,$parstack,$safeeval,'index');
         if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
      }
      return $result;
   }
   
   sub end_functionplotcustomrule {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      my $result='';
      if ($target eq 'edit') {
         $result=&Apache::edit::end_table();
      } elsif ($target eq 'grade') {
   # Simply remember - in order - for later
         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;
         }
         push(@Apache::functionplotresponse::functionplotvectorrules,join(':',(
              $label,
              'custom',
              &escape($Apache::response::custom_answer[-1])
             )));
      }
      &Apache::lonxml::deregister('Apache::response',('answer'));
      return $result;
   }
   
   
   
 #  #
 # <spline label="..." order="1,2,3,4" initx="..." inity="..." scalex="..." scaley="..." />  # <spline index="..." order="1,2,3,4" initx="..." inity="..." scalex="..." scaley="..." />
 #  #
 # Unfortunately, GeoGebra seems to want all splines after everything else, so we need to store them  # Unfortunately, GeoGebra seems to want all splines after everything else, so we need to store them
 #  #
Line 371  sub start_spline { Line 986  sub start_spline {
    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
    my $result='';     my $result='';
    if ($target eq 'web') {     if ($target eq 'web') {
       my $label=&Apache::lonxml::get_param('label',$parstack,$safeeval);        my $label=&Apache::lonxml::get_param('index',$parstack,$safeeval);
       $Apache::functionplotresponse::counter++;        $Apache::functionplotresponse::counter++;
       if ($label=~/\W/) {        if ($label=~/\W/) {
          &Apache::lonxml::warning(&mt('Spline labels should only contain alphanumeric characters.'));           &Apache::lonxml::warning(&mt('Spline indices should only contain alphanumeric characters.'));
       }        }
       $label=~s/\W//gs;        $label=~s/\W//gs;
       unless ($label) { $label='S'.$Apache::functionplotresponse::counter; }        unless ($label) { 
            $label='S'.$Apache::functionplotresponse::counter; 
         } else {
            $label='S'.$label;
         }
       if ($Apache::functionplotresponse::splineorder{$label}) {        if ($Apache::functionplotresponse::splineorder{$label}) {
          &Apache::lonxml::error(&mt('Spline labels must be unique.'));           &Apache::lonxml::error(&mt('Spline indices must be unique.'));
       }        }
   
       my $order=&Apache::lonxml::get_param('order',$parstack,$safeeval);        my $order=&Apache::lonxml::get_param('order',$parstack,$safeeval);
Line 404  sub start_spline { Line 1023  sub start_spline {
       $Apache::functionplotresponse::splinescaley{$label}=$sy;        $Apache::functionplotresponse::splinescaley{$label}=$sy;
    } elsif ($target eq 'edit') {     } elsif ($target eq 'edit') {
         $result=&Apache::edit::tag_start($target,$token,'Spline').          $result=&Apache::edit::tag_start($target,$token,'Spline').
              &Apache::edit::text_arg('Label:','label',               &Apache::edit::text_arg('Index:','index',
                                      $token,'4').'&nbsp;'.                                       $token,'4').'&nbsp;'.
              &Apache::edit::select_arg('Order:','order',               &Apache::edit::select_arg('Order:','order',
                                   ['2','3','4','5','6','7','8','9'],$token).'&nbsp;'.                                    ['2','3','4','5','6','7','8'],$token).'&nbsp;'.
              &Apache::edit::text_arg('Initial x-value:','initx',               &Apache::edit::text_arg('Initial x-value:','initx',
                                      $token,'4').'&nbsp;'.                                       $token,'4').'&nbsp;'.
              &Apache::edit::text_arg('Initial y-value:','inity',               &Apache::edit::text_arg('Initial y-value:','inity',
Line 419  sub start_spline { Line 1038  sub start_spline {
              &Apache::edit::end_row();               &Apache::edit::end_row();
   } elsif ($target eq 'modified') {    } elsif ($target eq 'modified') {
     my $constructtag=&Apache::edit::get_new_args($token,$parstack,      my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                                                  $safeeval,'label','order','initx','inity',                                                   $safeeval,'index','order','initx','inity',
                                                            'scalex','scaley');                                                             'scalex','scaley');
     if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }      if ($constructtag) { $result=&Apache::edit::rebuild_tag($token); }
   }    }
Line 474  sub get_answer_from_form_fields { Line 1093  sub get_answer_from_form_fields {
   
 sub cubic_hermite {  sub cubic_hermite {
    my ($t,$p1,$s1,$p2,$s2)=@_;     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)+     return (2.*$t*$t*$t-3.*$t*$t+1.)*$p1 + 3.*($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);            (-2.*$t*$t*$t+3.*$t*$t)  *$p2 + 3.*($t*$t*$t-$t*$t)      *($s2-$p2);
 }  }
   
 #  #
Line 484  sub cubic_hermite { Line 1103  sub cubic_hermite {
   
 sub ddt_cubic_hermite {  sub ddt_cubic_hermite {
    my ($t,$p1,$s1,$p2,$s2)=@_;     my ($t,$p1,$s1,$p2,$s2)=@_;
    return (6.*$t*$t-6.*$t) *$p1 + 5.*(3.*$t*$t-4.*$t+1.)*($s1-$p1)+     return (6.*$t*$t-6.*$t) *$p1 + 3.*(3.*$t*$t-4.*$t+1.)*($s1-$p1)+
           (-6.*$t*$t+6.*$t)*$p2 + 5.*(3.*$t*$t-2.*$t)   *($s2-$p2);            (-6.*$t*$t+6.*$t)*$p2 + 3.*(3.*$t*$t-2.*$t)   *($s2-$p2);
 }  }
   
 #  #
Line 494  sub ddt_cubic_hermite { Line 1113  sub ddt_cubic_hermite {
   
 sub d2dt2_cubic_hermite {  sub d2dt2_cubic_hermite {
    my ($t,$p1,$s1,$p2,$s2)=@_;     my ($t,$p1,$s1,$p2,$s2)=@_;
    return (12.*$t-6.) *$p1 + 5.*(6.*$t-4.)*($s1-$p1)+     return (12.*$t-6.) *$p1 + 3.*(6.*$t-4.)*($s1-$p1)+
           (-12.*$t+6.)*$p2 + 5.*(6.*$t-2.)*($s2-$p2);            (-12.*$t+6.)*$p2 + 3.*(6.*$t-2.)*($s2-$p2);
 }  }
   
 #  #
 # Implentation of <functionplotresponse>  # Array index calculation
   #
   sub array_index {
      my ($xmin,$xmax,$x)=@_;
      if ($x ne '') {
         return int(($x-$xmin)/($xmax-$xmin)*400.+0.5);
      } else {
         return undef;
      }
   }
   
   #
   # Populate the arrays
   #
   
   sub populate_arrays {
       my ($id,$xmin,$xmax,$ymin,$ymax)=@_;
       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)) {
                      $xiold=$xi;
                      $Apache::functionplotresponse::actualxval[$xi]=$xreal;
   # Function value
                      my $funcval=&cubic_hermite($t,@yparms);
   
   # Do we already have a value for this point, and is it different from the new one?
                      if ((defined($Apache::functionplotresponse::func[$xi])) &&
                          (abs($Apache::functionplotresponse::func[$xi]-$funcval)>($ymax-$ymin)/100.)) { 
                          return 'no_func'; 
                      }
   # Okay, remember the new point
                      $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 <functionplotresponse>
 #  #
   
 sub start_functionplotresponse {  sub start_functionplotresponse {
Line 515  sub start_functionplotresponse { Line 1216  sub start_functionplotresponse {
   undef %Apache::functionplotresponse::previous;    undef %Apache::functionplotresponse::previous;
   $Apache::functionplotresponse::inputfields='';    $Apache::functionplotresponse::inputfields='';
   $Apache::functionplotresponse::counter=0;    $Apache::functionplotresponse::counter=0;
   # Remember rules
     undef @Apache::functionplotresponse::functionplotrules;
     undef @Apache::functionplotresponse::functionplotvectorrules;
   # Remember failed rules
     if ($target eq 'grade') {
        undef @Apache::functionplotresponse::failedrules;
     }
   # Delete previous awards
     undef $Apache::functionplotresponse::awarddetail;
 # Part and ID  # Part and ID
   my $partid=$Apache::inputtags::part;    my $partid=$Apache::inputtags::part;
   my $id=&Apache::response::start_response($parstack,$safeeval);    my $id=&Apache::response::start_response($parstack,$safeeval);
Line 524  sub start_functionplotresponse { Line 1234  sub start_functionplotresponse {
   &decode_previous_answer($Apache::lonhomework::history{"resource.$partid.$id.submission"});    &decode_previous_answer($Apache::lonhomework::history{"resource.$partid.$id.submission"});
   
 # Parameters of <functionplotresponse>  # Parameters of <functionplotresponse>
   my $xmin=&Apache::lonxml::get_param('xmin',$parstack,$safeeval);    my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval);
   $xmin=($xmin?$xmin:-10);  
   my $xmax=&Apache::lonxml::get_param('xmax',$parstack,$safeeval);  
   $xmax=($xmax?$xmax:10);  
   my $ymin=&Apache::lonxml::get_param('ymin',$parstack,$safeeval);  
   $ymin=($ymin?$ymin:-10);  
   my $ymax=&Apache::lonxml::get_param('ymax',$parstack,$safeeval);  
   $ymax=($ymax?$ymax:10);  
   my $xaxisvisible=(&Apache::lonxml::get_param('xaxisvisible',$parstack,$safeeval)=~/on|true|yes|1/i?'true':'false');    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 $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 $gridvisible=(&Apache::lonxml::get_param('gridvisible',$parstack,$safeeval)=~/on|true|yes|1/i?'true':'false');
Line 541  sub start_functionplotresponse { Line 1244  sub start_functionplotresponse {
     $result.=&Apache::edit::start_table($token)      $result.=&Apache::edit::start_table($token)
        .'<tr><td><span class="LC_nobreak">'.&mt('Function Plot Question').'</span></td>'         .'<tr><td><span class="LC_nobreak">'.&mt('Function Plot Question').'</span></td>'
        .'<td><span class="LC_nobreak">'.&mt('Delete?').' '         .'<td><span class="LC_nobreak">'.&mt('Delete?').' '
        .&Apache::edit::deletelist($target,$token)         .&Apache::edit::deletelist($target,$token).'&nbsp;&nbsp;&nbsp;'
          .&Apache::edit::insertlist($target,$token).'&nbsp;&nbsp;&nbsp;'
          .&Apache::loncommon::help_open_topic('Function_Plot_Response_Question','Function Plot Responses')
        .'</span></td>'         .'</span></td>'
        ."<td>&nbsp;"         ."<td>&nbsp;"
        .&Apache::edit::end_row()         .&Apache::edit::end_row()
        .&Apache::edit::start_spanning_row()         .&Apache::edit::start_spanning_row()
        ."\n";         ."\n";
     $result.=&Apache::edit::text_arg('Label x-axis:','xlabel',      $result.=&Apache::edit::text_arg('Width (pixels):','width',
                                        $token,'6').'&nbsp;'.
                &Apache::edit::text_arg('Height (pixels):','height',
                                        $token,'6').'<br />'.
                &Apache::edit::text_arg('Label x-axis:','xlabel',
                                      $token,'6').'&nbsp;'.                                       $token,'6').'&nbsp;'.
              &Apache::edit::text_arg('Minimum x-value:','xmin',               &Apache::edit::text_arg('Minimum x-value:','xmin',
                                      $token,'4').'&nbsp;'.                                       $token,'4').'&nbsp;'.
              &Apache::edit::text_arg('Maximum x-value:','xmax',               &Apache::edit::text_arg('Maximum x-value:','xmax',
                                      $token,'4').'&nbsp;'.                                       $token,'4').'&nbsp;'.
              &Apache::edit::select_arg('x-axis visible:','xaxisvisible',               &Apache::edit::select_arg('x-axis visible:','xaxisvisible',
                                   ['yes','no'],$token).'&nbsp;&nbsp;'.                                    ['yes','no'],$token).'<br />'.
              &Apache::edit::text_arg('Label y-axis:','ylabel',               &Apache::edit::text_arg('Label y-axis:','ylabel',
                                      $token,'6').'&nbsp;'.                                       $token,'6').'&nbsp;'.
              &Apache::edit::text_arg('Minimum y-value:','ymin',               &Apache::edit::text_arg('Minimum y-value:','ymin',
Line 562  sub start_functionplotresponse { Line 1271  sub start_functionplotresponse {
              &Apache::edit::text_arg('Maximum y-value:','ymax',               &Apache::edit::text_arg('Maximum y-value:','ymax',
                                      $token,'4').'&nbsp;'.                                       $token,'4').'&nbsp;'.
              &Apache::edit::select_arg('y-axis visible:','yaxisvisible',               &Apache::edit::select_arg('y-axis visible:','yaxisvisible',
                                   ['yes','no'],$token).'&nbsp;&nbsp;'.                                    ['yes','no'],$token).'<br />'.
              &Apache::edit::select_arg('Grid visible:','gridvisible',               &Apache::edit::select_arg('Grid visible:','gridvisible',
                                   ['yes','no'],$token).                                    ['yes','no'],$token).'<br />'.
                &Apache::edit::text_arg('Background plot(s) for answer (function(x):xmin:xmax,function(x):xmin:xmax,x1:y1:sx1:sy1:x2:y2:sx2:sy2,...):',
                                            'answerdisplay',$token,'50').
              &Apache::edit::end_row().&Apache::edit::start_spanning_row();               &Apache::edit::end_row().&Apache::edit::start_spanning_row();
   } elsif ($target eq 'modified') {    } elsif ($target eq 'modified') {
     my $constructtag=&Apache::edit::get_new_args($token,$parstack,      my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                                                  $safeeval,'xlabel','xmin','xmax','ylabel','ymin','ymax',                                                   $safeeval,'width','height','xlabel','xmin','xmax','ylabel','ymin','ymax',
                                                            'xaxisvisible','yaxisvisible','gridvisible');                                                             'xaxisvisible','yaxisvisible','gridvisible','answerdisplay');
     if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }      if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
   
   } elsif ($target eq 'meta') {    } elsif ($target eq 'meta') {
        $result=&Apache::response::meta_package_write('functionplotresponse');         $result=&Apache::response::meta_package_write('functionplotresponse');
   } elsif ($target eq 'web') {    } elsif (($target eq 'answer') &&
 # paste in the update routine to receive stuff back from the applet              ($env{'form.answer_output_mode'} ne 'tex') &&
      $result.=&update_script($internalid);              ($Apache::lonhomework::viewgrades == 'F')) {
 # start the initscript for this applet        my (undef,undef,$udom,$uname)=&Apache::lonnet::whichuser();
      $result.=&start_init_script($internalid);        $uname =~s/\W//g;
 # put the axis commands inside        $udom  =~s/\W//g;
      $result.=&axes_script($internalid,$xmin,$xmax,$ymin,$ymax,$xaxisvisible,$yaxisvisible,$gridvisible);        my $function_name =
      $result.=&axes_label($internalid,$xlabel,$ylabel);                  join('_','LONCAPA_scriptvars',$uname,$udom,
 # init script is left open                       $env{'form.counter'},$Apache::lonxml::curdepth);
         &Apache::lonxml::add_script_result(
             &Apache::loncommon::modal_adhoc_window($function_name,700,500,
                '<pre>'.$Apache::functionplotresponse::ruleslog.'</pre>',
                 &mt('Rules Log'))."<br />");
   }    }
   return $result;    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)=@_;
      $text=~s/\'/\\\'/g;
      $Apache::functionplotresponse::ruleslog.=$text.'<br />';
   }
   
   sub actualval {
      my ($i,$xmin,$xmax)=@_;
      return $xmin+$i/400.*($xmax-$xmin);
   }
   
   sub fpr_val {
      my ($arg)=@_;
      return &actualval($Apache::functionplotresponse::functionplotrulelabels{$arg},
                        $Apache::functionplotresponse::fpr_xmin,
                        $Apache::functionplotresponse::fpr_xmax);
   }
   
   sub fpr_f {
      my ($arg)=@_;
      return $Apache::functionplotresponse::func[&array_index($Apache::functionplotresponse::fpr_xmin,
                                                              $Apache::functionplotresponse::fpr_xmax,
                                                              $arg)];
   }
   
   sub fpr_dfdx {
      my ($arg)=@_;
      return $Apache::functionplotresponse::dfuncdx[&array_index($Apache::functionplotresponse::fpr_xmin,
                                                                 $Apache::functionplotresponse::fpr_xmax,
                                                                 $arg)];
   }
   
   sub fpr_d2fdx2 {
      my ($arg)=@_;
      return $Apache::functionplotresponse::d2funcdx2[&array_index($Apache::functionplotresponse::fpr_xmin,
                                                                   $Apache::functionplotresponse::fpr_xmax,
                                                                   $arg)];
   }
   
   sub fpr_vectorcoords {
      my ($arg)=@_;
      $arg=~s/\W//gs;
      $arg=ucfirst($arg);
      my $id=$Apache::inputtags::response[-1];
      my $partid=$Apache::inputtags::part;
      my $internalid = $partid.'_'.$id;
      return ($env{'form.HWVAL_'.$internalid.'_'.$arg.'Start_x'},
              $env{'form.HWVAL_'.$internalid.'_'.$arg.'End_x'},
              $env{'form.HWVAL_'.$internalid.'_'.$arg.'Start_y'},
              $env{'form.HWVAL_'.$internalid.'_'.$arg.'End_y'});
   }
   
   sub fpr_objectcoords {
      my ($arg)=@_;
      $arg=~s/\W//gs;
      $arg=ucfirst($arg);
      my $id=$Apache::inputtags::response[-1];
      my $partid=$Apache::inputtags::part;
      my $internalid = $partid.'_'.$id;
      return ($env{'form.HWVAL_'.$internalid.'_'.$arg.'_x'},
              $env{'form.HWVAL_'.$internalid.'_'.$arg.'_y'});
   }
   
   sub fpr_vectorlength {
      my ($arg)=@_;
      my ($xs,$xe,$ys,$ye)=&fpr_vectorcoords($arg);
      return sqrt(($xe-$xs)*($xe-$xs)+($ye-$ys)*($ye-$ys));
   }
   
   sub fpr_vectorangle {
      my ($arg)=@_;
      my ($xs,$xe,$ys,$ye)=&fpr_vectorcoords($arg);
      my $angle=57.2957795*atan2(($ye-$ys),($xe-$xs));
      if ($angle<0) { $angle=360+$angle; }
      return $angle;
   }
   
   sub vectorcoords {
      my ($id,$label)=@_;
      return ($env{'form.HWVAL_'.$id.'_'.$label.'Start_x'},
              $env{'form.HWVAL_'.$id.'_'.$label.'End_x'},
              $env{'form.HWVAL_'.$id.'_'.$label.'Start_y'},
              $env{'form.HWVAL_'.$id.'_'.$label.'End_y'});
   }
   
   sub objectcoords {
      my ($id,$label)=@_;
      return ($env{'form.HWVAL_'.$id.'_'.$label.'_x'},
              $env{'form.HWVAL_'.$id.'_'.$label.'_y'});
   }
   
   sub attached {
      my ($id,$vector,$objects,$xmin,$xmax,$ymin,$ymax)=@_;
      my ($xs,$xe,$ys,$ye)=&vectorcoords($id,$vector);
      my $tolx=($xmax-$xmin)/100.;
      my $toly=($ymax-$ymin)/100.;
      my $tail=0;
      my $tip=0;
      foreach my $obj (split(/\s*\,\s*/,$objects)) {
         $obj=~s/\W//g;
         unless ($obj) { next; }
         $obj=ucfirst($obj);
         my ($xo,$yo)=&objectcoords($id,$obj);
         &addlog("Proximity $vector ($xs,$ys)-($xe,$ye) to $obj ($xo,$yo)");
         if ((abs($xs-$xo)<$tolx) && (abs($ys-$yo)<$toly)) {
            $tail=1;
            &addlog("Attached tail: $obj"); 
         }
         if ((abs($xe-$xo)<$tolx) && (abs($ye-$yo)<$toly)) { 
            $tip=1;
            &addlog("Attached tip: $obj"); 
         }
      }
      &addlog("Result tail:$tail tip:$tip");
      return($tail,$tip);
   }
   
    
   sub vectorangle {
      my ($x,$y)=@_;
      my $angle=57.2957795*atan2($y,$x);
      if ($angle<0) { $angle=360+$angle; }
      return $angle;
   }
   
   sub vectorlength {
      my ($x,$y)=@_;
      return sqrt($x*$x+$y*$y);
   }
   
   sub relvector {
      my ($xs,$xe,$ys,$ye)=@_;
      return ($xe-$xs,$ye-$ys);
   }
   
   sub plotvectorlength {
      return &vectorlength(&relvector(&vectorcoords(@_)));
   }
   
   sub plotvectorangle {
      return &vectorangle(&relvector(&vectorcoords(@_)));
   }
   
   
   #
   # Evaluate a functionplotvectorrule
   #
   
   sub functionplotvectorrulecheck {
      my ($rule,$xmin,$xmax,$ymin,$ymax,$safeeval)=@_;
      &addlog("=================");
      my ($label,$type)=split(/\:/,$rule);
      if ($type eq 'vector') {
         return &vectorcheck($rule,$xmin,$xmax,$ymin,$ymax,$safeeval);
      } elsif ($type eq 'sum') {
         return &sumcheck($rule,$xmin,$xmax,$ymin,$ymax,$safeeval);
      } elsif ($type eq 'custom') {
         return &customcheck($rule,$safeeval);
      }
   }
   
   sub vectorcheck {
      my ($rule,$xmin,$xmax,$ymin,$ymax,$safeeval)=@_;
      my ($label,$type,$id,$vector,
          $attachpoint,$notattachpoint,
          $tailpoint,$tippoint,$nottailpoint,$nottippoint,
          $length,$angle,$lengtherror,$angleerror)=split(/\:/,$rule);
      &addlog("Vector Rule $label for vector ".$vector);
      if ($length ne '') {
         &addlog("Checking for length $length with error $lengtherror");
         $length=&Apache::run::run($length,$safeeval);
         &addlog("Length evaluated to $length");
         my $thislength=&plotvectorlength($id,$vector);
         &addlog("Found length $thislength");
         if (abs($thislength-$length)>$lengtherror) {
            &setfailed($label);
            return 0;
         }
      }
      if ($angle ne '') {
         &addlog("Checking for angle $angle with error $angleerror");
         $angle=&Apache::run::run($angle,$safeeval);
         &addlog("Angle evaluated to $angle");
         my $thisangle=&plotvectorangle($id,$vector);
         &addlog("Found angle $thisangle");
         my $anglediff=abs($thisangle-$angle);
         &addlog("Angle difference: $anglediff");
         if ($anglediff>360.-$anglediff) {
            $anglediff=360.-$anglediff;
         }
         &addlog("Smallest angle difference: $anglediff");
         if ($anglediff>$angleerror) {
            &setfailed($label);
            return 0;
         }
      }
      if ($attachpoint ne '') {
         &addlog("Checking attached: ".$attachpoint);
         my ($tail,$tip)=&attached($id,$vector,$attachpoint,$xmin,$xmax,$ymin,$ymax);
         unless ($tail || $tip) {
            &setfailed($label);
            return 0;
         }
      }
      if ($notattachpoint ne '') {
         &addlog("Checking not attached: ".$notattachpoint);
         my ($tail,$tip)=&attached($id,$vector,$notattachpoint,$xmin,$xmax,$ymin,$ymax);
         if ($tail || $tip) {
            &setfailed($label);
            return 0;
         }
      }
      if ($tailpoint ne '') {
         &addlog("Checking tail: ".$tailpoint);
         my ($tail,$tip)=&attached($id,$vector,$tailpoint,$xmin,$xmax,$ymin,$ymax);
         unless ($tail) {
            &setfailed($label);
            return 0;
         }
      }
      if ($nottailpoint ne '') {
         &addlog("Checking not tail: ".$nottailpoint);
         my ($tail,$tip)=&attached($id,$vector,$nottailpoint,$xmin,$xmax,$ymin,$ymax);
         if ($tail) {
            &setfailed($label);
            return 0;
         }
      }
      if ($tippoint ne '') {
         &addlog("Checking tip: ".$tippoint);
         my ($tail,$tip)=&attached($id,$vector,$tippoint,$xmin,$xmax,$ymin,$ymax);
         unless ($tip) {
            &setfailed($label);
            return 0;
         }
      }
      if ($nottippoint ne '') {
         &addlog("Checking not tip: ".$nottippoint);
         my ($tail,$tip)=&attached($id,$vector,$nottippoint,$xmin,$xmax,$ymin,$ymax);
         if ($tip) {
            &setfailed($label);
            return 0;
         }
      }
   
      &addlog("Rule $label passed.");
      return 1;
   }
   
   sub sumcheck {
      my ($rule,$xmin,$xmax,$ymin,$ymax,$safeeval)=@_;
      my ($label,$type,$id,$vectors,$length,$angle,$lengtherror,$angleerror)=split(/\:/,$rule);
      &addlog("Vector Sum Rule $label for vectors ".$vectors);
      my $sumx=0;
      my $sumy=0;
      foreach my $sv (split(/\s*\,\s*/,$vectors)) {
         my ($rx,$ry)=&relvector(&vectorcoords($id,$sv));
         $sumx+=$rx;
         $sumy+=$ry;
      }
      &addlog("Sum vector ($sumx,$sumy)");
      if ($length ne '') {
         &addlog("Checking length $length with error $lengtherror");
         $length=&Apache::run::run($length,$safeeval);
         &addlog("Evaluated to $length");
         my $thislength=&vectorlength($sumx,$sumy);
         &addlog("Actual length $thislength");
         if (abs($length-$thislength)>$lengtherror) {
                     &setfailed($label);
            return 0;
         }
      }
      if ($angle ne '') {
         &addlog("Checking angle $angle with error $angleerror");
         $angle=&Apache::run::run($angle,$safeeval);
         &addlog("Evaluated to $angle");
         my $thisangle=&vectorangle($sumx,$sumy);
         &addlog("Actual angle $thisangle");
         my $anglediff=abs($thisangle-$angle);
         &addlog("Angle difference: $anglediff");
         if ($anglediff>360.-$anglediff) {
            $anglediff=360.-$anglediff;
         }
         &addlog("Smallest angle difference: $anglediff");
         if ($anglediff>$angleerror) {
            &setfailed($label);
            return 0;
         }
      }
      &addlog("Rule $label passed.");
      return 1;
   }
   
   sub customcheck {
      my ($rule,$safeeval)=@_;
      my ($label,$type,$prg)=split(/\:/,$rule);
      &addlog("Custom Rule ".$label);
      my $result=&Apache::run::run(&unescape($prg),$safeeval);
      &addlog("Algorithm returned $result");
      unless ($result) {
         &setfailed($label);
         return 0;
      }
      &addlog("Rule $label passed.");
      return 1;
   }
   
   #
   # Evaluate a functionplotrule
   #
    
   sub functionplotrulecheck {
      my ($rule,$xmin,$xmax,$ymin,$ymax,$safeeval)=@_;
   
      my ($label,$derivative,$xinitial,$xinitiallabel,$xfinal,$xfinallabel,$minimumlength,$maximumlength,$relationship,$value,$percent)
         =split(/\:/,$rule);
      $percent=($percent>0?$percent:5);
      &addlog("=================");
      &addlog("Rule $label for ".($derivative<0?'integral':('function itself','first derivative','second derivative')[$derivative])." $relationship $value");
   #
   # Evaluate the value
   #
      if ($value=~/\D/) {
         $Apache::functionplotresponse::fpr_xmin=$xmin;
         $Apache::functionplotresponse::fpr_xmax=$xmax;
         $value=&Apache::run::run($value,$safeeval);
         &addlog("Value evaluated to $value");
      }
   
   #
   # Minimum and maximum lengths of the interval
   #
      if ((defined($minimumlength)) || (defined($maximumlength))) {
         &addlog("Minimumlength $minimumlength Maximumlength $maximumlength");
      }
      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) || (!defined($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);
         } elsif ($derivative==-1) {
            $tol=$tol*($xmax-$xmin)/2.;
         }
      }
      my $integral=0;
      my $binwidth=($xmax-$xmin)/400.;
      if (($derivative<0) && (!$findupper)) {
   # definite integral, calculate over whole length
        &addlog("Calculating definite integral");
        for (my $i=$li; $i<=$lh; $i++) {
           $integral+=$Apache::functionplotresponse::func[$i]*$binwidth;
        }
        unless (&compare_rel($relationship,$value,$integral,$tol)) {
           &addlog("Actual integral ".(defined($integral)?$integral:'undef').", expected $value, tolerance $tol");
           &addlog("Rule $label failed.");
           &setfailed($label);
           return 0;
        } 
      } else {
        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];
           } elsif ($derivative==-1) {
              $integral+=$Apache::functionplotresponse::func[$i]*$binwidth;
              $val=$integral;      
           } 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 lengths
                 unless (&checklength($i,$li,$minimumlength,$maximumlength,$xmin,$xmax,$label)) { return 0; }
   # Successfully found a new label, set it
                 $Apache::functionplotresponse::functionplotrulelabels{$xfinallabel}=$i;
                 &addlog("Rule $label passed, setting label $xfinallabel");
                 return 1;
              } else {
                 &addlog("Rule $label failed.");
                 &setfailed($label);
                 return 0; 
              }
           }
        }
      }
   # Corner case where this makes sense: using start or stop as defined labels
      unless (&checklength($lh,$li,$minimumlength,$maximumlength,$xmin,$xmax,$label)) { return 0; }
      &addlog("Rule $label passed.");
      return 1;
   }
   
   #
   # check for minimum and maximum lengths
   #
   
   sub checklength {
       my ($i,$li,$minimumlength,$maximumlength,$xmin,$xmax,$label)=@_;
       unless (($minimumlength) || ($maximumlength)) { return 1; }
       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");
             &setfailed($label);
             return 0;
          }
       }
       if ($maximumlength) {
          if ($length>$maximumlength) {
             &addlog("Rule $label failed, actual length $length, maximum length $maximumlength");
             &setfailed($label);
             return 0;
          }
       }
       return 1;
   }
   
   sub setfailed {
      my ($hintlabel)=@_;
      $hintlabel=~s/^R//;
      push(@Apache::functionplotresponse::failedrules,$hintlabel);
      &addlog("Set hint condition $hintlabel");
   }
   
   sub start_functionplotruleset {
      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
      if ($target eq 'edit') {
         return &Apache::edit::start_table($token).
           '<tr><td><span class="LC_nobreak">'.&mt('Function Plot Rule Set').'</span></td>'
          .'<td><span class="LC_nobreak">'.&mt('Delete?').' '
          .&Apache::edit::deletelist($target,$token).'&nbsp;&nbsp;&nbsp;'.
           &Apache::edit::insertlist($target,$token).'&nbsp;&nbsp;&nbsp;'
          .&Apache::loncommon::help_open_topic('Function_Plot_Response_Rule_Set','Function Plot Rules')
          .'</span></td>'
          ."<td>&nbsp;"
          .&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,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-2);
   
           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,$ymin,$ymax) 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,$safeeval)) {
                    $ad='INCORRECT';
                    last;
                 }
              }
   # And now go through the vector rules
              foreach my $rule (@Apache::functionplotresponse::functionplotvectorrules) {
                 unless (&functionplotvectorrulecheck($rule,$xmin,$xmax,$ymin,$ymax,$safeeval)) {
                    $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 {  sub end_functionplotresponse {
   my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   &Apache::response::end_response;    &Apache::response::end_response;
Line 601  sub end_functionplotresponse { Line 1910  sub end_functionplotresponse {
          && &Apache::response::submitted()           && &Apache::response::submitted()
          && $Apache::lonhomework::type eq 'exam') {           && $Apache::lonhomework::type eq 'exam') {
   
         #&Apache::response::scored_response($partid,$id);          &Apache::response::scored_response($partid,$id);
   
     } elsif ($target eq 'grade'      } elsif ($target eq 'grade'
          && &Apache::response::submitted()           && &Apache::response::submitted()
Line 610  sub end_functionplotresponse { Line 1919  sub end_functionplotresponse {
         $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;          $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;
         my %previous=&Apache::response::check_for_previous($response,$partid,$id);          my %previous=&Apache::response::check_for_previous($response,$partid,$id);
 #  #
 # Actually grade  # Assign grade
 #  #
         my $ad='INCORRECT';          my $ad=$Apache::functionplotresponse::awarddetail;
 #  #
 # Store grading info  # Store grading info
 #  #
         $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;          $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;
         &Apache::response::handle_previous(\%previous,$ad);          &Apache::response::handle_previous(\%previous,$ad);
    } elsif ($target eq 'web') {     } 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') {
        my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-2);
   
   # Are we in show answer mode?
        my $showanswer=&Apache::response::show_answer();
        if ($showanswer) {
   # Render answerdisplay
           my $answerdisplay=&Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval,-2);
           if ($answerdisplay=~/\S/s) {
              foreach my $plot (split(/\s*\,\s*/,$answerdisplay)) {
                 my @components=split(/\s*\:\s*/,$plot);
                 if ($#components<3) {
   # Just a simple plot
                    my ($func,$xl,$xh)=@components;
                    if ((!defined($xl)) || ($xl eq '')) { $xl=$xmin; }
                    if ((!defined($xh)) || ($xh eq '')) { $xh=$xmax; }
                    $result.=&plot_script($internalid,$func,1,'','00aa00',$xl,$xh,6);
                 } else {
   # This is a spline
                    $result.=&answer_spline_script($internalid,@components);
                 }
              }
           }
        }
        my $fixed=0;
        if (($showanswer) || (&Apache::response::check_status()>=2)) { $fixed=1; }
 # Now is the time to render all of the stored splines  # Now is the time to render all of the stored splines
      foreach my $label (keys(%Apache::functionplotresponse::splineorder)) {       foreach my $label (keys(%Apache::functionplotresponse::splineorder)) {
         $result.=&generate_spline($internalid,$label);          $result.=&generate_spline($internalid,$label,$xmin,$xmax,$ymin,$ymax,$fixed);
      }       }
 # close the init script  # close the init script
      $result.=&end_init_script();       $result.=&end_init_script();
Line 635  sub end_functionplotresponse { Line 1983  sub end_functionplotresponse {
 # generate the input fields  # generate the input fields
      $result.=$Apache::functionplotresponse::inputfields;       $result.=$Apache::functionplotresponse::inputfields;
 # actually start the <applet>-tag  # actually start the <applet>-tag
      $result.=&geogebra_startcode($internalid);       $result.=&geogebra_startcode($internalid,
                                     &Apache::lonxml::get_param('width',$parstack,$safeeval,-2),
                                     &Apache::lonxml::get_param('height',$parstack,$safeeval,-2));
 # load the spline bytecode  # load the spline bytecode
      $result.=&geogebra_spline_program();       $result.=&geogebra_spline_program();
 # set default parameters  # set default parameters
Line 645  sub end_functionplotresponse { Line 1995  sub end_functionplotresponse {
   }    }
   return $result;    return $result;
 }  }
   
   sub boundaries {
      my ($parstack,$safeeval,$level)=@_;
      my $xmin=&Apache::lonxml::get_param('xmin',$parstack,$safeeval,$level);
      $xmin=(defined($xmin)?$xmin:-10);
      my $xmax=&Apache::lonxml::get_param('xmax',$parstack,$safeeval,$level);
      $xmax=(defined($xmax)?$xmax:10);
      my $ymin=&Apache::lonxml::get_param('ymin',$parstack,$safeeval,$level);
      $ymin=(defined($ymin)?$ymin:-10);
      my $ymax=&Apache::lonxml::get_param('ymax',$parstack,$safeeval,$level);
      $ymax=(defined($ymax)?$ymax:10);
      if ($xmax<=$xmin) {
         $xmax=$xmin+20;
      }
      if ($ymax<=$ymin) {
         $ymax=$ymin+20;
      }
      return ($xmin,$xmax,$ymin,$ymax);
   }
   
   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).
           '<tr><td><span class="LC_nobreak">'.&mt('Function Plot Elements').'</span></td>'
          .'<td><span class="LC_nobreak">'.&mt('Delete?').' '
          .&Apache::edit::deletelist($target,$token).'&nbsp;&nbsp;&nbsp;'.
           &Apache::edit::insertlist($target,$token).'&nbsp;&nbsp;&nbsp;'
          .&Apache::loncommon::help_open_topic('Function_Plot_Response_Elements','Function Plot Elements')
          .'</span></td>'
          ."<td>&nbsp;"
          .&Apache::edit::end_row()
          .&Apache::edit::start_spanning_row()
          ."\n";
      } elsif ($target eq 'web') {
         my ($xmin,$xmax,$ymin,$ymax)=&boundaries($parstack,$safeeval,-2);
         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,$xmin,$xmax,$ymin,$ymax,$xlabel,$ylabel);
   # init script is left open
     }
     return $result;
   }
   
 1;  1;
   

Removed from v.1.17  
changed lines
  Added in v.1.90


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
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.