/*
ASCII2MathML-SVGPlotFunctions.js v3.41, May 13th 2009
=====================================================================
Copyright Dr.ir. S.A. Miedema, www.Fullxml.org

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.

This program 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 Lesser General Public License 
(at http://www.gnu.org/licences/lgpl.html) for more details.
*/

function plot(fun,x_min,x_max,points,id,endpts) {
  if (TypeOfGraph==LinearLinear) plotlinlin(fun,x_min,x_max,points,id,endpts);
  if (TypeOfGraph==LinearLogaritmic) plotlinlog(fun,x_min,x_max,points,id,endpts);
  if (TypeOfGraph==LogaritmicLinear) plotloglin(fun,x_min,x_max,points,id,endpts);
  if (TypeOfGraph==LogaritmicLogaritmic) plotloglog(fun,x_min,x_max,points,id,endpts);
  if (TypeOfGraph==Polar) plotlinlin(fun,x_min,x_max,points,id,endpts);
} 

function plotlinlin(fun,x_min,x_max,points,id,endpts) {
  var x, y, name;
  var pth = [];
  var f = function(x) { return x }, g = fun;
  if (typeof fun=="string") 
    eval("g = function(x){ return "+mathjs(fun)+" }");
  else if (typeof fun=="object") {
    eval("f = function(t){ return "+mathjs(fun[0])+" }");
    eval("g = function(t){ return "+mathjs(fun[1])+" }");
  }
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  for (var t = min; t <= max; t += inc) {
    x = f(t);
    if (x<=xmin) x = xmin;
    if (x>=xmax) x = xmax;
    y = g(t);
    if (y>=ymax) y = ymax; 
    if (y<=ymin) y = ymin; 
  	if (isFinite(y)) pth[pth.length] = [x, y];
  }
  path(pth,name,null,endpts);
  return pth;
}

function plotlinlog(fun,x_min,x_max,points,id,endpts) {
  var x, y, name;
  var pth = [];
  var f = function(x) { return x }, g = fun;
  if (typeof fun=="string") 
    eval("g = function(x){ return "+mathjs(fun)+" }");
  else if (typeof fun=="object") {
    eval("f = function(t){ return "+mathjs(fun[0])+" }");
    eval("g = function(t){ return "+mathjs(fun[1])+" }");
  }
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    x = f(t);
    if (x<=xmin) x = xmin;
    if (x>=xmax) x = xmax;
    y = g(pow(10,t));
    if (y>=ymax) y = ymax; 
    if (y<=ymin) y = ymin; 
  	if (isFinite(y)) pth[pth.length] = [x, y];
  }
  path(pth,name,null,endpts);
  return pth;
}

function plotloglin(fun,x_min,x_max,points,id,endpts) {
  var x, y, name;
  var pth = [];
  var f = function(x) { return x }, g = fun;
  if (typeof fun=="string") 
    eval("g = function(x){ return "+mathjs(fun)+" }");
  else if (typeof fun=="object") {
    eval("f = function(t){ return "+mathjs(fun[0])+" }");
    eval("g = function(t){ return "+mathjs(fun[1])+" }");
  }
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    x = f(t);
    if (x<=xmin) x = xmin;
    if (x>=xmax) x = xmax;
    y = log(g(t));
    if (y>=ymax) y = ymax; 
    if (y<=ymin) y = ymin; 
   	if (isFinite(y)) pth[pth.length] = [x, y];
  }
  path(pth,name,null,endpts);
  return pth;
}

function plotloglog(fun,x_min,x_max,points,id,endpts) {
  var x, y, name;
  var pth = [];
  var f = function(x) { return x }, g = fun;
  if (typeof fun=="string") 
    eval("g = function(x){ return "+mathjs(fun)+" }");
  else if (typeof fun=="object") {
    eval("f = function(t){ return "+mathjs(fun[0])+" }");
    eval("g = function(t){ return "+mathjs(fun[1])+" }");
  }
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    x = f(t);
    if (x<=xmin) x = xmin;
    if (x>=xmax) x = xmax;
    y = log(g(pow(10,t)));
    if (y>=ymax) y = ymax; 
    if (y<=ymin) y = ymin; 
   	if (isFinite(y)) pth[pth.length] = [x, y];
  }
  path(pth,name,null,endpts);
  return pth;
}

// make polar plot
function polarplot(fun,x_min,x_max,points,id,endpts) {
  var polarfunx,polarfuny;
  polarfunx=fun+"*cos(t)";
  polarfuny=fun+"*sin(t)";
  plotlinlin([polarfunx, polarfuny],x_min,x_max,points,id,endpts);
}

function areaplot(fun,x_min,x_max,points,id,endpts) {
  var t, u, name;
  var ft, gt;
  var pth = [], pth2 = [];
  if (typeof fun=="object") {
    eval("f = function(t){ return "+mathjs(fun[0])+" }");
    eval("g = function(t){ return "+mathjs(fun[1])+" }");
  }
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  for (var t = min; t <= max; t += inc) {
    ft = f(t);
    u = min + max - t;
    gt = g(u);
    if (ft>=ymax) ft = ymax; 
    if (ft<=ymin) ft = ymin; 
    if (gt>=ymax) gt = ymax; 
    if (gt<=ymin) gt = ymin; 
    if (t<=xmin) t = xmin;
    if (t>=xmax) t = xmax;
    if (u<=xmin) u = xmin;
    if (u>=xmax) u = xmax;
  	if (isFinite(ft)) pth[pth.length] = [t, ft];
  	if (isFinite(gt)) pth2[pth2.length] = [u, gt];
  }
  pth = pth.concat(pth2);
  path(pth,name,null,endpts,true);
  return pth;
}

/// bezier curve
function beziercubic(p1, p2, q, id) {
  var str;
  str = "M";
  str += (p1[0]*xunitlength+origin[0])+","+(height-p1[1]*yunitlength-origin[1])+" ";
  str += "Q";
  str += (q[0]*xunitlength+origin[0])+","+(height-q[1]*yunitlength-origin[1])+" ";
  str += (p2[0]*xunitlength+origin[0])+","+(height-p2[1]*yunitlength-origin[1])+" ";
  bezier(str,id);
}

function bezierquadratic(p1,q1,p2,q2,id) {
  var str;
  str = "M";
  str += (p1[0]*xunitlength+origin[0])+","+(height-p1[1]*yunitlength-origin[1])+" ";
  str += "C";
  str += (q1[0]*xunitlength+origin[0])+","+(height-q1[1]*yunitlength-origin[1])+" ";
  str += (q2[0]*xunitlength+origin[0])+","+(height-q2[1]*yunitlength-origin[1])+" ";
  str += (p2[0]*xunitlength+origin[0])+","+(height-p2[1]*yunitlength-origin[1])+" ";
  bezier(str,id);
}

function bezier(str, id) {
  var node;
  if (id!=null) node = doc.getElementById(id);
  if (node==null) {
    node = myCreateElementSVG("path");
    node.setAttribute("id", id);
    svgpicture.appendChild(node);
  }
  node.setAttribute("d", str);
  setSVGStroke(node);
  setSVGNoFill(node);
}

function svgPath(str, id) {
  var node;
  if (id!=null) node = doc.getElementById(id);
  if (node==null) {
    node = myCreateElementSVG("path");
    node.setAttribute("id", id);
    svgpicture.appendChild(node);
  }
  node.setAttribute("d", str);
  setSVGStroke(node);
  setSVGFill(node);
}

function slopefield(fun,dx,dy) {
  var g = fun;
  if (typeof fun=="string") 
    eval("g = function(x,y){ return "+mathjs(fun)+" }");
  var gxy,x,y,u,v,dz;
  if (dx==null) dx=1;
  if (dy==null) dy=1;
  dz = Math.sqrt(dx*dx+dy*dy)/6;
  var x_min = Math.ceil(xmin/dx);
  var y_min = Math.ceil(ymin/dy);
  for (x = x_min; x <= xmax; x += dx)
    for (y = y_min; y <= ymax; y += dy) {
      gxy = g(x,y);
      if (!isNaN(gxy)) {
        if (Math.abs(gxy)=="Infinity") {u = 0; v = dz;}
        else {u = dz/Math.sqrt(1+gxy*gxy); v = gxy*u;}
        line([x-u,y-v],[x+u,y+v]);
      }
    }
}

function differentiate(fun,x_min,x_max,points,id,endpts) {
  var pth = [];
  var f = function(x) { return x }, g = fun;
  var name = null;
  if (typeof fun=="string") eval("g = function(x){ return "+mathjs(fun)+" }");
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    gt = (g(t+inc)-g(t-inc))/(2*inc);
    if (gt<=ymax && gt>=ymin) {
    	if (isFinite(gt)) pth[pth.length] = [f(t), gt];
    }
    if (gt>ymax) pth[pth.length] = [f(t),ymax];
    if (gt<ymin) pth[pth.length] = [f(t),ymin];
  }
  path(pth,name,null,endpts);
  return p;
}

function differentiate2(fun,x_min,x_max,points,id,endpts) {
  var pth = [];
  var f = function(x) { return x }, g = fun;
  var name = null;
  if (typeof fun=="string") eval("g = function(x){ return "+mathjs(fun)+" }");
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/200:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    gt = ((g(t+inc)-g(t))/inc -(g(t)-g(t-inc))/inc)/inc;
    if (gt<=ymax && gt>=ymin) {
    	if (isFinite(gt)) pth[pth.length] = [f(t), gt];
    }
    if (gt>ymax) pth[pth.length] = [f(t),ymax];
    if (gt<ymin) pth[pth.length] = [f(t),ymin];
  }
  path(pth,name,null,endpts);
  return p;
}

function initintegrate(startvalue,startvalue2) {
  integral = startvalue;
  if (startvalue2!=null) integral2 = startvalue2;
}

function integrate(fun,x_min,x_max,points,id,endpts) {
  var pth = [];
  var f = function(x) { return x }, g = fun;
  var name = null;
  if (typeof fun=="string") eval("g = function(x){ return "+mathjs(fun)+" }");
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/1000:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    integral = (g(t+inc)+g(t-inc))/2*inc+integral;
    gt = integral;
    if (gt<=ymax && gt>=ymin) {
    	if (isFinite(gt)) pth[pth.length] = [f(t), gt];
    }
    if (gt>ymax) pth[pth.length] = [f(t),ymax];
    if (gt<ymin) pth[pth.length] = [f(t),ymin];
  }
  path(pth,name,null,endpts);
  return p;
}

function integrate2(fun,x_min,x_max,points,id,endpts) {
  var pth = [];
  var f = function(x) { return x }, g = fun;
  var name = null;
  if (typeof fun=="string") eval("g = function(x){ return "+mathjs(fun)+" }");
  if (typeof x_min=="string") { name = x_min; x_min = xmin }
  else name = id;
  var min = (x_min==null?xmin:x_min);
  var max = (x_max==null?xmax:x_max);
  var inc = max-min-0.000001*(max-min);
  inc = (points==null?inc/2000:inc/points);
  var gt;
  for (var t = min; t <= max; t += inc) {
    integral = (g(t+inc)+g(t-inc))/2*inc+integral;
    integral2 = integral*inc+integral2;
    gt = integral2;
    if (gt<=ymax && gt>=ymin) {
    	if (isFinite(gt)) pth[pth.length] = [f(t), gt];
    }
    if (gt>ymax) pth[pth.length] = [f(t),ymax];
    if (gt<ymin) pth[pth.length] = [f(t),ymin];
  }
  path(pth,name,null,endpts);
  return p;
}

function initDotPlot() {
  dotitems = [];
}

function addDotItem(x, y, dottype, label, position,id) {
  if (label==null) label="";
  if (position==null) position="rightmiddle";
  dotitems[dotitems.length] = [x, y, dottype, label, position, id];
}

function plotDots() {
  var numberofitems, item;
  numberofitems = dotitems.length;
  for (item = 0; item<numberofitems; item = item+1) {
    dot([dotitems[item][0],dotitems[item][1]],dotitems[item][2],dotitems[item][3],dotitems[item][4],dotitems[item][5]);
  }
}