• fullscreen
  • ComplexNumber.pde
  • ComplexNumberTransformations.pde
  • Delegate.pde
  • Functions.pde
  • Interaction.pde
  • Screens.pde
  • public class ComplexNumber
    {
      float real = 0f;
      float imaginary = 0f;
      
      public ComplexNumber(){}
      
      public ComplexNumber(float real, float imaginary)
      {
        this.real = real;
        this.imaginary = imaginary;
      }
      
      
      
      public ComplexNumber getConjugate()
      {
        return new ComplexNumber(real, -imaginary);
      }
      
      public float getModulus()
      {
        return dist(0,0,real,imaginary);
      }
      
      public float getArgument()
      {
        return atan2(imaginary, real);
      }
      
      
      
      public ComplexNumber Add(ComplexNumber cn)
      {
        return new ComplexNumber(real + cn.real, imaginary + cn.imaginary);
      }
      
      public ComplexNumber Add(float num)
      {
        return new ComplexNumber(real + num, imaginary);
      }
      
      public ComplexNumber Subtract(ComplexNumber cn)
      {
        return new ComplexNumber(real - cn.real, imaginary - cn.imaginary);
      }
      
      public ComplexNumber Subtract(float num)
      {
        return new ComplexNumber(real - num, imaginary);
      }
      
      public ComplexNumber Multiply(ComplexNumber cn)
      {
        return new ComplexNumber(real * cn.real - imaginary * cn.imaginary, real * cn.imaginary + imaginary * cn.real);
      }
      
      public ComplexNumber Multiply(float num)
      {
        return new ComplexNumber(real * num, imaginary * num);
      }
      
      public ComplexNumber Divide(ComplexNumber cn)
      {
        float divisor = cn.real * cn.real + cn.imaginary * cn.imaginary;
        return new ComplexNumber((real * cn.real + imaginary * cn.imaginary) / divisor, (imaginary * cn.real - real * cn.imaginary) / divisor);
      }
      
      public ComplexNumber Divide(float f)
      {
        return new ComplexNumber(real / f, imaginary / f);
      }
      
      public ComplexNumber Power(int power)
      {
        ComplexNumber orig = Clone();
        ComplexNumber cn = Clone();
        for(int i = 0; i < power - 1; i++)
          cn = cn.Multiply(orig);
        
        return cn;      
      }
      
      public ComplexNumber Power(float power)
      {
        float arg = power * getArgument();
        float mod = pow(getModulus(), power);
        
        return new ComplexNumber(mod * cos(arg), mod * sin(arg));
      }
      
      public ComplexNumber[] Roots(int n)
      {
        float arg = getArgument();
        float mod = getModulus();
        float mul = pow(mod, 1/(float)n);
        ComplexNumber[] cns = new ComplexNumber[n];
        
        for(int i = 0; i < n; i++)
        {
          float theta = (arg + 2*i*PI)/n;
          cns[i] = new ComplexNumber(mul * cos(theta), mul * sin(theta));
        }
        
        return cns;
      }
      
      
      
      public void DrawPoint()
      {
        point(real, imaginary);
      }
      
      
      
      public ComplexNumber Clone()
      {
        return new ComplexNumber(real, imaginary);
      }
      
      public Complex Convert()
      {
        return new Complex((double)real, (double)imaginary);
      }
      
      public String toString()
      {
        return (real + ((imaginary>=0)?"+":"-") + abs(imaginary) + "i");
      }
      
      public String toString(int format)
      {
        String ret = "";
        
        switch(format)
        {
          case ComplexFormats.Cartesian: ret = toString(); break;
          case ComplexFormats.Trigonometric: ret = toString("r(cos a + isin a)"); break;
          case ComplexFormats.Polar: ret = toString("[r,a]"); break;
          case ComplexFormats.Exponential: ret = toString("r e^ai"); break;
        }
        
        return ret;
      }
      
      public String toString(String format)
      {
        return format.replaceAll("r", Float.toString(getModulus()))
                     .replaceAll("a", Float.toString(getArgument()))
                     .replaceAll("x", Float.toString(real))
                     .replaceAll("y", Float.toString(imaginary));    
      }
    }
    
    public static final class ComplexFormats
    {
      public static final int Cartesian = 0;
      public static final int Trigonometric = 1;
      public static final int Polar = 2;
      public static final int Exponential = 3;
    }
    
    import java.util.*;
    import java.util.regex.*;
    
    // http://www.superstable.net/interfascia/
    import interfascia.*;
    
    // http://sourceforge.net/projects/jep/
    import org.nfunk.jep.evaluation.*;
    import org.nfunk.jep.*;
    import org.nfunk.jep.function.*;
    import org.nfunk.jep.type.*;
    
    float zooml = 1, zoomr = 1, h;
    float offsetrx=0, offsetry=0, offsetlx=0, offsetly=0;
    boolean drawing = false;
    boolean numberPoints = false;
    boolean drawNow = false;
    boolean drawAxis = false; // Obselete
    boolean drawAxisLines = true; // For preview picture purposes only xD
    boolean showExamples = false;
    int display = Display.Normal;
    PFont font, calibri, calibri25, calibri14;
    
    ComplexDelegate transform = new ComplexDelegate() { ComplexNumber Invoke(ComplexNumber cn) { return cn.Power(2); } };
    ArrayDelegate input = new ArrayDelegate() { ArrayList[] Invoke() { return createGrid(-300, -300, 300, 300, 10, 10); } };
    //ArrayDelegate input = new ArrayDelegate() { ArrayList[] Invoke() { return createCircle(0,0,1,1,1000,PI/128); } };
    //ArrayDelegate input = new ArrayDelegate() { ArrayList[] Invoke() { return createFilledCircle(0,0,1,1,600,25,PI/100); } };
    //ArrayDelegate input = new ArrayDelegate() { ArrayList[] Invoke() { return createLine(-300,-300,300,300,10); } };
    //ArrayDelegate input = new ArrayDelegate() { ArrayList[] Invoke() { return createFormula("x^2/100",-100,100,1); } };
    
    org.nfunk.jep.JEP parser = new org.nfunk.jep.JEP();
    org.nfunk.jep.JEP inputParser = new org.nfunk.jep.JEP();
    org.nfunk.jep.JEP fParser = new org.nfunk.jep.JEP();
    
    ArrayList arr = new ArrayList();
    ArrayList fills = new ArrayList();
    ArrayList complexs = new ArrayList();
    
    String inputTransOrig;
    
    void setup()
    {
      size(900,550);
      //size(1200,700); // For larger screens
      h=height-100;
      smooth();
      background(255);
      stroke(0);
      noStroke();
      fill(0);
      //noFill();
      font = loadFont("LucidaConsole-10.vlw");
      calibri = loadFont("Calibri-30.vlw");
      calibri14 = loadFont("Calibri-14.vlw");
      calibri25 = loadFont("Calibri-25.vlw");
      textFont(font);
      drawNow = true;
      
      InitialiseGUI();
      
      parser.addComplex();
      parser.addStandardConstants();  
      parser.addStandardFunctions();
      parser.addFunction("root", new Root());
      
      inputParser.addStandardConstants();
      inputParser.addStandardFunctions();
      inputParser.addFunction("grid", new Grid());
      inputParser.addFunction("circle", new Circle());
      inputParser.addFunction("ellipse", new Ellipse());
      inputParser.addFunction("filledCircle", new FilledCircle());
      inputParser.addFunction("filledEllipse", new FilledEllipse());
      inputParser.addFunction("line", new Line());
      inputParser.addFunction("func",new Circle());
      
      fParser.addStandardConstants();
      fParser.addStandardFunctions();
      
    }
    
    void draw()
    {
      if(display == Display.FunctionHelp)
      {
        background(255);
        drawFunctionHelpGUI();
      }
      else if(display == Display.Examples)
      {
        background(255);
        drawExamplesGUI();
      }
      else if(display == Display.Help)
      {
        background(255);
        drawHelpGUI();
      }
      else
      {  
        CheckCenterMouse();
      
        if(drawNow)
        {
          drawGraphGUI();
          drawNow = false;
        }
        
        fill(255);
        rect(0,h,width,height-h);
      }
    }
    
    void drawGraphGUI()
    {
      drawing = true;
      fill(255);
      rect(0,0,width,h);
      textFont(font);
      textSize(10);
      textAlign(CENTER);
      
      arr.clear();
      fills.clear();
      
      if(arr.size() == 0)
        CalculateInitials();
      
      for(int i = 0; i < arr.size(); i++)
      {
        noStroke();
        ComplexNumber cn = (ComplexNumber)arr.get(i);
        Color c = (Color)fills.get(i);
        fill(c.getRed(), c.getGreen(), c.getBlue());
        if(ClampChoose(-width/4,width/4,cn.real*zooml+offsetlx) && ClampChoose(-h/2 - 10, h/2 + 10, cn.imaginary*zooml-offsetly))
          {
            ellipse(width/4 + cn.real*zooml+offsetlx, h/2 - cn.imaginary*zooml+offsetly,4,4);
            if(numberPoints)
              text(i, width/4 + cn.real*zooml+offsetlx, h/2 - cn.imaginary*zooml+offsetly - 4);
          }
      }
      
      if(complexs.size() == 0)
      {
        CalculateComplexs();
      }
      
      for(int i = 0; i < arr.size(); i++)
      {    
        ComplexNumber cn = (ComplexNumber)complexs.get(i);
        Color c = (Color)fills.get(i);
        fill(c.getRed(), c.getGreen(), c.getBlue());
          if(ClampChoose(-width/4,width/4,cn.real*zoomr+offsetrx) && ClampChoose(-h/2 - 10, h/2 + 10, cn.imaginary*zoomr-offsetry))
          {
            ellipse(width*3/4 + cn.real*zoomr+offsetrx, h/2 - cn.imaginary*zoomr+offsetry,4,4);
            if(numberPoints)
            {
              text(i, width*3/4 + cn.real*zoomr+offsetrx, h/2 - cn.imaginary*zoomr+offsetry - 4);
            }
          }
      }
    
      stroke(0);
      strokeWeight(3);
      line(width/2,0,width/2,h);
      line(0,h,width,h);
      
      strokeWeight(1);
      
      if(drawAxisLines)
      {
      if(width/4+offsetlx < width/2)
        line(width/4+offsetlx,0,width/4+offsetlx,h);
      if(width*3/4+offsetrx > width/2)
        line(width*3/4+offsetrx,0,width*3/4+offsetrx,h);
      line(0,h/2+offsetly,width/2,h/2+offsetly);
      line(width/2,h/2+offsetry,width,h/2+offsetry);
      }
      
      fill(0);
      
      if(drawAxis)
      {
        for(float i = width/4 + offsetlx; i > 0 ; i -= 50)
        {
          if(ClampChoose(0,width/4 + offsetlx,width/4 + offsetlx - i))
            text("-" + Round(i/10/zooml,2),width/4 + offsetlx - i,h/2 + offsetly + 10);
        } 
        for(float i = 0; i <= width/4 + offsetlx; i += 50)
        {
          if(ClampChoose(width/4 + offsetlx,width/2,width/4 + offsetlx + i))
            text(Round(i/10/zooml,2),width/4 + offsetlx + i,h/2 + offsetly + 10);
        } 
      }
      
      labelsr[1].setLabel(zoomr + "x");
      labelsr[3].setLabel(Float.toString(offsetrx));
      labelsr[5].setLabel(Float.toString(offsetry));
      
      labelsl[1].setLabel(zooml + "x");
      labelsl[3].setLabel(Float.toString(offsetlx));
      labelsl[5].setLabel(Float.toString(offsetly));
    
      drawing = false;
    }
    
    String Round(float num, int decimals)
    {
      String str = Float.toString(round(pow(10,decimals)*num)/pow(10,decimals));
      return str.substring(0,str.length());
    }
    
    void ChangeIntialDelegate(String change)
    {
      inputParser.parseExpression(change);
      if((inputParser.getValue() == -1))
      {
        inputError.setValue("Error: incorrect syntax");
      }
      else if(Double.isNaN(inputParser.getValue()))
      {
        inputError.setValue("Error: expression cannot be solved.");
      }
      else
      {
        CalculateInitials();
      }
    }
    
    void CalculateInitials()
    {
      ArrayList[] ret = input.Invoke();
      arr = ret[0];
      fills = ret[1];
    }
    
    ArrayList[] createGrid(float xs, float ys, float xe, float ye, float xstep, float ystep)
    { 
      ArrayList[] ret = new ArrayList[2];
      ret[0] = new ArrayList();
      ret[1] = new ArrayList();
      
      for(float i = xs; i < xe; i += xstep)
      {
        for(float j = ys; j <= ye; j += ystep)
        {
          Color c = new Color(0,100+(abs((int)i)%50)*3,100+(abs((int)j)%50)*3);
          ComplexNumber cn = new ComplexNumber(i/10,j/10);
          ret[0].add(cn);
          ret[1].add(c);
        }
      }
        
      return ret;
    }
    
    ArrayList[] createCircle(float x, float y, float xstrech, float ystrech, float r, float ang)
    {
      ArrayList[] ret = new ArrayList[2];
      ret[0] = new ArrayList();
      ret[1] = new ArrayList();
      
      for(float i = 0; i < TWO_PI; i += ang)
      {
        Color c = new Color(0,100+(int)((i*1000)%100),150);
        ComplexNumber cn = new ComplexNumber(xstrech*(x+r*cos(i))/10,ystrech*(y+r*sin(i))/10);
        ret[0].add(cn);
        ret[1].add(c);
      }
      
      return ret;
    }
    
    ArrayList[] createFilledCircle(float x, float y, float xstrech, float ystrech, float r, float gap, float ang)
    {
      ArrayList[] ret = new ArrayList[2];
      ret[0] = new ArrayList();
      ret[1] = new ArrayList();
      
      for(float i = gap; i < r; i += gap)
      {
        for(float j = 0; j < TWO_PI; j += ang)
        {
          Color c = new Color(0,100+(int)(i%100),200-(int)(j%100));
          ComplexNumber cn = new ComplexNumber(xstrech*(x+i*cos(j))/10,ystrech*(y+i*sin(j))/10);
          ret[0].add(cn);
          ret[1].add(c);
        }
      }
      
      return ret;
    }
    
    ArrayList[] createLine(float xs, float ys, float xe, float ye, float gap)
    {
      ArrayList[] ret = new ArrayList[2];
      ret[0] = new ArrayList();
      ret[1] = new ArrayList();
      
      if(xe-xs == 0)
      {
        for(float i = 0; i < abs(ye-ys); i += gap)
        {
          Color c = new Color(0,100+(int)(i%100),150);
          ComplexNumber cn = new ComplexNumber(xs, ys + i);
          ret[0].add(cn);
          ret[1].add(c);
        }
      }
      else
      {
        float gradient = (ye - ys)/(xe - xs); 
        for(float i = 0; i < abs(xe-xs); i += gap)
        {
          Color c = new Color(0,50+100*(int)(i/abs(xe-xs)),125);
          ComplexNumber cn = new ComplexNumber(xs + i, ys + i*gradient);
          ret[0].add(cn);
          ret[1].add(c);
        }
      }
      
      return ret;
    }
    
    ArrayList[] createFormula(String formula, float xs, float xe, float dx)
    {
      ArrayList[] ret = new ArrayList[2];
      ret[0] = new ArrayList();
      ret[1] = new ArrayList();
      
      for(float i = xs; i < xe; i += dx)
      {
        Color c = new Color(0,100+(int)(i%75),100+(int)(i%63));
        ComplexNumber cn = new ComplexNumber(i,evalFormula(formula,i));
        ret[0].add(cn);
        ret[1].add(c);
      }
      
      return ret;
    }
    
    float evalFormula(String formula, float x)
    {
      fParser.addVariable("x",(double)x);
      fParser.parseExpression(formula);
      return (float)fParser.getValue();
    }
    
    void CalculateComplexs()
    {
      ArrayList stor = (ArrayList)complexs.clone();
      complexs.clear();
      boolean fail = false;
      float step = arr.size()/20;
        for(int i = 0; i < arr.size(); i++)
        {
          if(i % step == 0)
            println("Complexs: " + Float.toString(round(100*(float)i/arr.size())) + " %");
          ComplexNumber cn = (ComplexNumber)arr.get(i);
          ComplexNumber tcn = transform.Invoke(cn);
          if((tcn.real == Float.MAX_VALUE) && (tcn.imaginary == Float.MAX_VALUE))
          {
            fail = true;
            complexs = stor;
            break;
          }
          else
          {
            complexs.add(tcn);
          }
        }
      status("Complexs: 100.0 %");
      if(fail == false)
        outputError.setValue("Finished Calculation");
    }
    
    ComplexNumber evalString(String str, ComplexNumber cn, String var)
    {  
      if(str.trim() != "")
      {
        parser.addVariable(var, (double)cn.real, (double)cn.imaginary);
        parser.parseExpression(str);
        Complex c = parser.getComplexValue();
        if(c == null)
        {
          outputError.setValue("Error: incorrect syntax");
          return new ComplexNumber(Float.MAX_VALUE, Float.MAX_VALUE);
        }
        else
          return new ComplexNumber((float)c.re(), (float)c.im());
      }
      else
        return cn;
    }
    
    boolean ClampChoose(float min, float max, float num)
    {
      boolean ret = true;
    
      if(num < min) ret = false;
      else if(num > max) ret = false;
    
      return ret;
    }
    
    
    
    public interface ComplexDelegate
    {
      ComplexNumber Invoke(ComplexNumber cn);
    }
    
    public interface ArrayDelegate
    {
      ArrayList[] Invoke();
    }
    
    public class Core
    {
      public ComplexNumber Convert(Complex c)
      {
        return new ComplexNumber((float)c.re(), (float)c.im());
      }
      
      public ComplexNumber Convert(Number n)
      {
        return new ComplexNumber(n.floatValue(), 0);
      }
    }
    
    public static final class Display
    {
      static final int Normal = 0;
      static final int Examples = 1;
      static final int Help = 2;
      static final int FunctionHelp = 3;
    }
    
    public class Grid extends PostfixMathCommand
    {
      public Grid()
      {
        numberOfParameters = 6;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
        
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createGrid( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue(), ((Number)t[4]).floatValue(), ((Number)t[5]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    public class Circle extends PostfixMathCommand
    {
      public Circle()
      {
        numberOfParameters = 4;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
        
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createCircle( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), 1, 1, ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    public class Ellipse extends PostfixMathCommand
    {
      public Ellipse()
      {
        numberOfParameters = 6;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {    
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
          
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createCircle( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue(), ((Number)t[4]).floatValue(), ((Number)t[5]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    
    public class FilledCircle extends PostfixMathCommand
    {
      public FilledCircle()
      {
        numberOfParameters = 5;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
        
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createFilledCircle( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), 1, 1, ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue(), ((Number)t[4]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    public class FilledEllipse extends PostfixMathCommand
    {
      public FilledEllipse()
      {
        numberOfParameters = 7;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {    
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
          
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createFilledCircle( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue(), ((Number)t[4]).floatValue(), ((Number)t[5]).floatValue(), ((Number)t[6]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    public class Line extends PostfixMathCommand
    {
      public Line()
      {
        numberOfParameters = 5;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {    
        checkStack(inStack);// check the stack
        final Object[] t = stackToObjectArray(inStack, numberOfParameters);
          
        if(checkAllNumber(t))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createLine( ((Number)t[0]).floatValue(), ((Number)t[1]).floatValue(), ((Number)t[2]).floatValue(), ((Number)t[3]).floatValue(), ((Number)t[4]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }
    
    /*public class Func extends PostfixMathCommand
    {
      public Func()
      {
        numberOfParameters = 4;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {    
        checkStack(inStack);// check the stack
        final Object st = inStack.pop();
        final Object[] p = stackToObjectArray(inStack, numberOfParameters-1);
        
        outputError.setValue(st + "\n" + p);
          
        if((st instanceof String) && (checkAllNumber(p)))
        {
          input = new ArrayDelegate() { ArrayList[] Invoke() { return createFormula((String)st, ((Number)p[0]).floatValue(), ((Number)p[1]).floatValue(), ((Number)p[2]).floatValue() ); } };
          inStack.push(new Double(0));
        }
        else
        {
          inStack.push(new Double(-1));
          throw new org.nfunk.jep.ParseException();
        }
      }
    }*/
    
    
    Object[] stackToObjectArray(Stack stack, int numberOfParameters)
    {
      ArrayList p = new ArrayList();
        
      for(int i = 0; i < numberOfParameters; i++)
      p.add(stack.pop());
        
      Collections.reverse(p);     
      return p.toArray(); 
    }
    
    
    boolean checkAllNumber(Object[] al)
    {
      boolean soFar = true;
      for(int i = 0; i < al.length; i++)
        soFar = soFar && (al[i] instanceof Number);
      return soFar;
    }
    
    
    
    
    
    
    public class Root extends PostfixMathCommand
    {
      public Root()
      {
        numberOfParameters = 3;
      }
      
      public void run(Stack inStack) throws org.nfunk.jep.ParseException 
      {		
        Core core = new Core();
        
        checkStack(inStack);// check the stack
        Object p3 = inStack.pop();
        Object p2 = inStack.pop();
        Object p1 = inStack.pop();
        Object out = new Object();    
        
        if((p2 instanceof Number) && (p3 instanceof Number))
        {
          if(p1 instanceof Complex)
             out = core.Convert((Complex)p1).Roots(((Number)p2).intValue())[((Number)p3).intValue()-1].Convert();
          else if(p1 instanceof Number)
             out = core.Convert((Number)p1).Roots(((Number)p2).intValue())[((Number)p3).intValue()-1].Convert();
        }
        else
        {
          throw new org.nfunk.jep.ParseException();
        }
        
        inStack.push(out);//push the result on the inStack
      }
    }
    
    GUIController guic;
    
    IFButton outputBtn;
    IFTextField outputTrans;
    IFLabel[] labelsr = new IFLabel[6]; 
    IFLabel[] labelsl = new IFLabel[6]; 
    IFButton resetBtnr;
    IFButton resetBtnl;
    IFTextField outputError;
    IFButton inputBtn;
    IFTextField inputTrans;
    IFTextField inputError;
    IFButton helpBtn;
    
    IFButton examplesBtn;
    GUIController guic_examples[];
    IFButton[] examplesBtns;
    IFButton functionHelpBtn;
    
    void InitialiseGUI()
    {
      guic = new GUIController(this);
      outputTrans = new IFTextField("output",width/2+15,(int)h+15,270);
      outputTrans.setValue("z^2");
      outputBtn = new IFButton("Do",outputTrans.getX() + outputTrans.getWidth() + 10,(int)h+15,60,20);  
      outputBtn.addActionListener(this);
      examplesBtn = new IFButton("Examples!",outputBtn.getX() + outputBtn.getWidth() + 10,outputBtn.getY(),80,20);
      examplesBtn.addActionListener(this);
    
      labelsr[0] = new IFLabel("Zoom Factor:",outputTrans.getX(), outputTrans.getY() + outputTrans.getHeight() + 15);
      labelsr[1] = new IFLabel("1x",outputTrans.getX() + 75, labelsr[0].getY());
      labelsr[2] = new IFLabel("Offset X:",labelsr[1].getX() + 100, labelsr[0].getY());
      labelsr[3] = new IFLabel("0",labelsr[2].getX() + 55, labelsr[0].getY());
      labelsr[4] = new IFLabel("Offset Y:",labelsr[3].getX() + 75, labelsr[0].getY());
      labelsr[5] = new IFLabel("0",labelsr[4].getX() + 55, labelsr[0].getY());
    
      resetBtnr = new IFButton("Reset",labelsr[0].getX(),labelsr[0].getY() + 20);
      resetBtnr.addActionListener(this);
    
      outputError = new IFTextField("",resetBtnr.getX() + resetBtnr.getWidth() + 45, resetBtnr.getY(),270);  
    
      inputTrans = new IFTextField("input",15,(int)h+15,300);
      inputTransOrig = "grid(-300, -300, 300, 300, 10, 10)";
      inputTrans.setValue(inputTransOrig);
      inputBtn = new IFButton("Do",inputTrans.getX() + inputTrans.getWidth() + 5,(int)h+15,60,20); 
      inputBtn.addActionListener(this);
      helpBtn = new IFButton("Help",inputBtn.getX() + inputBtn.getWidth() + 5,inputBtn.getY(),60,20);
      helpBtn.addActionListener(this);
    
      labelsl[0] = new IFLabel("Zoom Factor:",15, inputTrans.getY() + inputTrans.getHeight() + 15);
      labelsl[1] = new IFLabel("1x",labelsl[0].getX() + 75, labelsl[0].getY());
      labelsl[2] = new IFLabel("Offset X:",labelsl[1].getX() + 100, labelsl[0].getY());
      labelsl[3] = new IFLabel("0",labelsl[2].getX() + 55, labelsl[0].getY());
      labelsl[4] = new IFLabel("Offset Y:",labelsl[3].getX() + 75, labelsl[0].getY());
      labelsl[5] = new IFLabel("0",labelsl[4].getX() + 55, labelsl[0].getY());
    
      resetBtnl = new IFButton("Reset",labelsl[0].getX(),labelsl[0].getY() + 20);
      resetBtnl.addActionListener(this);
    
      inputError = new IFTextField("",resetBtnl.getX() + resetBtnl.getWidth() + 45, resetBtnl.getY(),270);
      
      functionHelpBtn = new IFButton("Function Help",width/2-105,55,100, 20);
      functionHelpBtn.addActionListener(this);
      
      // Evens are el, odds are er!!!!!  
      examplesBtns = new IFButton[el.length+er.length];
      guic_examples = new GUIController[el.length+er.length+1]; // +1 for the "Function Help" button.
      for(int i = 0; i < examplesBtns.length; i+=2)
      {
        examplesBtns[i] = new IFButton("Test", width/2-55, 255+i*10-3, 40, 20);
        examplesBtns[i].addActionListener(this);
        guic_examples[i] = new GUIController(this);
        
        examplesBtns[i+1] = new IFButton("Test", width-55, 255+i*10-3, 40, 20);
        examplesBtns[i+1].addActionListener(this);
        guic_examples[i+1] = new GUIController(this);
      }
      guic_examples[examplesBtns.length-1] = new GUIController(this);
    
      guic.add(outputTrans);
      guic.add(outputBtn);
      guic.add(examplesBtn);
      GUIControllerAddRange(guic,labelsr);
      guic.add(resetBtnr);
      guic.add(outputError);
    
      guic.add(inputTrans);
      guic.add(inputBtn);
      GUIControllerAddRange(guic,labelsl);
      guic.add(resetBtnl);
      guic.add(inputError);
      guic.add(helpBtn);
    }
    
    void GUIControllerAddRange(GUIController g, IFLabel[] ifs)
    {
      for(int i = 0; i < ifs.length; i++)
      {
        g.add(ifs[i]);
      }
    }
    
    void actionPerformed(GUIEvent e)
    {
      println("Component: " + e.getSource());
      println ("Message: " + e.getMessage());
    
      if(e.getSource() == outputBtn)
      {
        final String str = outputTrans.getValue();
        transform = new ComplexDelegate() { 
          ComplexNumber Invoke(ComplexNumber cn) { 
            return evalString(str,cn,"z"); 
          } 
        }; 
        rcd();
      }
      else if(e.getSource() == resetBtnr)
      {
        zoomr = 1;
        offsetrx = 0;
        offsetry = 0;
        rd();
      }
      else if(e.getSource() == inputBtn)
      {
        final String in = inputTrans.getValue().trim().replace(" ","");
        if(in.contains("func("))
        {
          Pattern pattern = Pattern.compile("func\\((.*),(\\-?[0-9\\.]*),(\\-?[0-9\\.]*),(\\-?[0-9\\.]*)\\)");
          Matcher m = pattern.matcher(in);
          if(m.matches())
          {
            final String[] s = new String[] { 
              m.group(1), m.group(2), m.group(3), m.group(4)         };
            input = new ArrayDelegate() { 
              ArrayList[] Invoke() { 
                return createFormula(s[0], Float.valueOf(s[1]).floatValue(), Float.valueOf(s[2]).floatValue(), Float.valueOf(s[3]).floatValue() ); 
              } 
            };
          }
          else
          {
            inputError.setValue("Error: format = func(eqn,num,num,num)");
          }
          CalculateInitials();
        }
        else
        {
          ChangeIntialDelegate(in);
        }
        rcd();
      }
      else if(e.getSource() == resetBtnl)
      {
        zooml = 1;
        offsetlx = 0;
        offsetly = 0;
        rd();
      }
      else if(e.getSource() == helpBtn)
      {
        if(display == Display.Normal)
          toHelp();
        else if(display == Display.Help)
          backFromHelp();
      }
      else if(e.getSource() == examplesBtn)
      {
        if(display == Display.Normal)
          toExamples();
        else if(display == Display.Examples)
          backFromExamples(); 
        else if(display == Display.FunctionHelp)
        {
          examplesBtn.setLabel("Examples!");
          display = Display.Normal;
          rd();
        }
      }
      else if(display == Display.Examples)
      {
        testExampleButtonActions(e);
      }
        
    }
    
    void toHelp()
    {
      helpBtn.setLabel("Back");
      display = Display.Help;
    }
    
    void backFromHelp()
    {
      helpBtn.setLabel("Help");
      display = Display.Normal;
      rd();
    }
    
    void toExamples()
    {
      examplesBtn.setLabel("Back!");
      display = Display.Examples;
      addTestExampleButtons();
    }
    
    void backFromExamples()
    {
      examplesBtn.setLabel("Examples!");
      display = Display.Normal;
      removeTestExampleButtons();
      rd();
    }
    
    void addTestExampleButtons()
    {
      for(int i = 0; i < examplesBtns.length; i++)
      {
        guic_examples[i].add(examplesBtns[i]);
      }
      guic_examples[examplesBtns.length-1].add(functionHelpBtn);
    }
    
    void removeTestExampleButtons()
    {
      for(int i = 0; i < examplesBtns.length; i++)
      {
        guic_examples[i].remove(examplesBtns[i]);
      }
      guic_examples[examplesBtns.length-1].remove(functionHelpBtn);
    }
    
    void testExampleButtonActions(GUIEvent guie)
    {
      if(guie.getSource() == functionHelpBtn)
      {
        removeTestExampleButtons();
        display = Display.FunctionHelp;
      }
      else
      {
        for(int i = 0; i < examplesBtns.length; i++)
        {
          if(guie.getSource() == examplesBtns[i])
          {
            backFromExamples();
            if(i%2 == 0)
            {
              inputTrans.setValue(el[i/2]);
              actionPerformed(new GUIEvent(inputBtn, "Clicked"));
            }
            else
            {
              outputTrans.setValue(er[(i-1)/2]);
              actionPerformed(new GUIEvent(outputBtn, "Clicked"));
            }
          }
        }
      }
    }
    
    void mousePressed()
    {
      if(display == Display.Normal)
      {
      switch(mouseButton)
      {
      case LEFT: 
        if(mouseY < h)
        {
          if((mouseX < width/2)) zooml *= 2;
          else zoomr *= 2;
          rd();
        }
        break;
      case RIGHT:
        if(mouseY < h)
        {
          if((mouseX < width/2)) zooml /= 2;
          else zoomr /= 2;
          rd();
        }
        break;
      }
      }
    }
    
    void CheckCenterMouse()
    {
      if(mousePressed && (mouseButton == CENTER))
      {
        if(mouseY < h)
        {
          if(mouseX < width/2)
          {
            boolean nox = false, noy = false;
    
            if(mouseX < width/6)
              offsetlx += 50;
            else if(mouseX > width*2/6)
              offsetlx -= 50;
            else
              nox = true;
    
            if(mouseY < h/3)
              offsetly += 50;
            else if(mouseY > h*2/3)
              offsetly -= 50;
            else
              noy = true;
    
            if(nox && noy)
            {
              if(mouseY < h/2)
                zooml *= 2;
              else
                zooml /= 2;
            }
            rd();
          }
    
          else if(mouseX > width/2)
          {
            boolean nox = false, noy = false;
    
            if(mouseX < width*4/6)
              offsetrx += 50;
            else if(mouseX > width*5/6)
              offsetrx -= 50;
            else
              nox = true;
    
            if(mouseY < h/3)
              offsetry += 50;
            else if(mouseY > h*2/3)
              offsetry -= 50;
            else
              noy = true;
    
            if(nox && noy)
            {
              if(mouseY < h/2)
                zoomr *= 2;
              else
                zoomr /= 2;
            }
            rd();
          }
        }
      }
    }
    
    void rd()
    {
      drawNow = true;
    }
    
    void rcd()
    {
      CalculateComplexs();
      drawNow = true;
    }
    
    void keyPressed()
    {
      if(!(guic.getFocusStatusForComponent(outputTrans) || guic.getFocusStatusForComponent(inputTrans)) && (display == Display.Normal))
        switch(key)
        {
        case 'n':  
          numberPoints = !numberPoints; 
          rcd(); 
          break;
        case '1':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Power(2); 
            } 
          }; 
          rcd(); 
          break;
        case '2':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Power(3); 
            } 
          }; 
          rcd(); 
          break;
        case '3':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return new ComplexNumber(1,0).Divide(cn.Add(1)); 
            } 
          }; 
          rcd(); 
          break;
        case '4':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return new ComplexNumber(1,0).Divide(cn.Power(2)); 
            } 
          }; 
          rcd(); 
          break;
        case '5':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return new ComplexNumber(1,0).Divide(cn.Roots(10)[1].Multiply(cn.Roots(10)[0]).Multiply(cn.Roots(10)[2])); 
            } 
          }; 
          rcd(); 
          break;
        case '6':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Divide(cn.getConjugate()); 
            } 
          }; 
          rcd(); 
          break;
        case '7':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Roots(3)[1].Multiply(cn.Roots(4)[3]); 
            } 
          }; 
          rcd(); 
          break;
        case '8':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.getConjugate().Add(cn).Divide(cn.Roots(11)[4]); 
            } 
          }; 
          rcd(); 
          break;
        case '9':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Roots(5)[2].Add(cn.Roots(2)[1]).Divide(cn.Add(40)); 
            } 
          }; 
          rcd(); 
          break;
        case '0':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Divide(cn.Roots(4)[3].getConjugate()).Divide(cn.Roots(4)[3]); 
            } 
          }; 
          rcd(); 
          break;
        case '-':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Divide(cn.getConjugate().Add(cn.Roots(4)[2].Multiply(cn.Roots(4)[0]))); 
            } 
          }; 
          rcd(); 
          break;
        case '=':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return cn.Power(2.7); 
            } 
          }; 
          rcd(); 
          break;
        case ']':  
          transform = new ComplexDelegate() { 
            ComplexNumber Invoke(ComplexNumber cn) { 
              return evalString("z^2.6",cn,"z"); 
            } 
          }; 
          rcd(); 
          break;
    
        case 'a': 
          offsetlx += 50; 
          rd(); 
          break;
        case 'w': 
          offsetly += 50; 
          rd(); 
          break;
        case 's': 
          offsetly -= 50; 
          rd(); 
          break;
        case 'd': 
          offsetlx -= 50; 
          rd(); 
          break;
    
        case 'j': 
          offsetrx += 50; 
          rd(); 
          break;
        case 'i': 
          offsetry += 50; 
          rd(); 
          break;
        case 'k': 
          offsetry -= 50; 
          rd(); 
          break;
        case 'l': 
          offsetrx -= 50; 
          rd(); 
          break;
    
        case 'z': 
          zooml *= 2; 
          rd(); 
          break;
          
        case 'x':
          zooml /= 2;
          rd();
          break;
          
        case 'm':
          zoomr *= 2;
          rd();
          break;
        
        case ',':
          zoomr /= 2;
          rd();
          break;
          
        }
    }
    
    
    String[] el = new String[]
      { 
        "grid(-300, -300, 300, 300, 5, 5)",
        "circle(0, 0, 300, pi/64)",
        "ellipse(0, 0, 3, 4, 300, pi/70)",
        "filledCircle(0, 0, 300, 15, pi/32)",
        "filledEllipse(0, 0, 3, 4, 300, 20, pi/100)",
        "line(100, -500, 100, 500, 5)",
        "func(x^2/100, -500, 500, 2)",
        "func(x^3/100, -500, 500, 2)",
        "func(300*sin(x/100), -5000, 5000, 2)",
        "func(10*(x % 11), -5000, 5000, 2)"
      };
      
    String[] er = new String[]
    {
      "z^2",
      "z^3",
      "1/z",
      "1/z^2",
      "root(z,5,1)*root(z,5,2)*root(z,5,3)",
      "z/conj(root(z,4,4))/root(z,4,4)",
      "z/(conj(z)+root(z,4,3))*root(z,4,1)",
      "z^0.4",
      "(z+1)^2/(z-1)^2",
      "conj(z)/conj(root(-z,7,2))"
    };
    
    String[] fe = new String[]
    {
      "grid(startx, starty, endx, endy, xgap, ygap)",
      "circle(centerx, centery, radius, angle_increment (in radians))",
      "ellipse(centerx, centery, xmultiply, ymultiply, radius, angle_inc_radians)",
      "filledCircle(centerx, centery, radius, gap, angle_inc)",
      "filledEllipse(centerx, centery, xmultiply, ymultiply, radius, gap, angle_inc)",
      "line(startx, starty, endx, endy, xgap)",
      "func(expression_in_x, start_x_value, end_x_value, x_increment)"
    };
    
    void drawExamplesGUI()
    {
      textFont(calibri);
      textSize(30);
      textAlign(LEFT, TOP);
      fill(0);
      
      text("Examples",15,15);
      
      textFont(calibri25);
      textSize(25);
      text("Input",15,55);
      text("Output",width/2 + 15,55);
      
      textFont(calibri14);
      textSize(14);
      
      for(int i = 0; i < fe.length; i++)
      {
        text(fe[i],15,95+i*20);
      }
      
      for(int i = 0; i < el.length; i++)
      {
        text(el[i],15,255+i*20);
      }
      
      float w = width/2+15;
      
      text("Trig:    sin(x), cos(x), tan(x), cosh(x), sinh(x), tanh(x)",w,95);
      text("Trig:    asin(x), acos(x), atan(x), acosh(x), asinh(x), atanh(x)",w,115);
      text("Logs:    log(x), ln(x), exp(x), mod(x,y) = x % y",w,135);
      text("Others:  abs(x), rand(x), sqrt(x), sum(x,y,z), if(condition,trueval,falseval)",w,155);
      text("Complex: re(z), im(z), cmod(z), arg(z), conj(z), complex(x,y), polar(r,theta)",w,175);
      text("Complex: root(z,x,y) - returns the yth complex xth root of unity of z",w,195);
      text("Constants:  e, pi, i",w,215);
      
      for(int i = 0; i < er.length; i++)
      {
        text(er[i],w,255+i*20);
      }
    }
    
    void drawHelpGUI()
    {
      textFont(calibri);
      textSize(30);
      textAlign(LEFT, TOP);
      fill(0);
      float w = width/2+15;
      float l = width/4+15;
      
      text("Help",15,15);
      
      textFont(calibri25);
      textSize(25);
      text("Controls",15,55);
      text("What are Complex Numbers?",w,55);
      text("What is the \"angle increment?\"",w,295);
      
      textFont(calibri14);
      textSize(14);
      
      text("W - Move left graph up", 15,95);
      text("A - Move left graph left", 15,115);
      text("S - Move left graph down", 15,135);
      text("D - Move left graph right", 15,155);
      
      text("I - Move right graph up",l,95);
      text("J - Move right graph left",l,115);
      text("K - Move right graph down",l,135);
      text("L - Move right graph right",l,155);
      
      text("N - Display numbers over each point",15,175);
      
      text("Left Click: Zoom in",15,205);
      text("Right Click: Zoom out",l,205);
      text("Z/X - Zoom in/out for the left graph",15,225);
      text("M/, - Zoom in/out for the right graph",l,225);
      
      text("Middle Click: Depends on where you click on the graph:",15,245);
      
      
      
      text("Complex Numbers are numbers that consist of a real number and an",w,95);
      text("imaginary number. An imaginary number is one that is a multiple of i,",w,115);
      text("where i is the square root of -1 (for example 3i or 4i). A real number",w,135);
      text("is one that your used to, like 2 or -6 or 5.333452. A complex number",w,155);
      text("is these two combined in the form \"a + bi\" (1 + 2i for example).",w,175);
      
      text("This program takes a set of these complex numbers (such as a grid) and then",w,205);
      text("applies some transformation to them, such as squaring them, and displays",w,225);
      text("the results on the right hand side. It can use functions like conj(z) to",w,245);
      text("find Conjugates and root() to find Complex Roots of Unity, as well as others.",w,265);
      
      
      
      
      text("When drawing a circle, this defines is how many points should be used to",w,335);
      text("create that circle. Simply use \"2*pi/x\" replacing x with the number of",w,355);
      text("points you want to use.",w,375);
      
      drawAngleIncrementExplaination(width*0.75,415,40,PI/8);
      
      drawMiddleClickExplaination(15,260,(h-250)*4/3,h-250);
    }
    
    void drawMiddleClickExplaination(float x, float y, float wi, float hi)
    {
      stroke(0);
      line(x,y,x+wi,y);
      line(x,y,x,y+hi);
      line(x+wi,y,x+wi,y+hi);
      line(x,y+hi,x+wi,y+hi);
      
      line(x+wi/2,y,x+wi/2,y+hi);
      line(x,y+hi/2,x+wi,y+hi/2);
      
      noStroke();
      fill(#F5B800, 200);
      
      rect(x,y,wi/3,hi);
      rect(x+wi*2/3,y,wi/3,hi);
      rect(x,y,wi,hi/3);
      rect(x,y+hi*2/3,wi,hi/3);
      
      fill(#B8F500, 200);  
      rect(x+wi/3, y+hi/3, wi/3,hi/6);
      fill(#00F5B8, 200);
      rect(x+wi/3, y+hi/2, wi/3,hi/6);
      
      fill(0);  
      textFont(calibri14);
      textSize(14);
      textAlign(CENTER, CENTER);
      
      text("Up and Left",x+wi/6, y+hi/6);
      text("Up",x+wi/2, y+hi/6);
      text("Up and Right",x+wi*5/6, y+hi/6);
      text("Left",x+wi/6, y+hi/2);
      text("Right",x+wi*5/6, y+hi/2);
      text("Down and Left",x+wi/6, y+hi*5/6);
      text("Down",x+wi/2, y+hi*5/6);
      text("Down and Right",x+wi*5/6, y+hi*5/6);
      
      text("Zoom In",x+wi/2, y+hi*5/12);
      text("Zoom Out",x+wi/2, y+hi*7/12);
    }
    
    void drawAngleIncrementExplaination(float x, float y, float radius, float angle)
    {
      textFont(calibri14);
      textSize(14);
      textAlign(LEFT, CENTER);
      
      angle -= PI/2;
      stroke(0);
      noFill();
      ellipse(x,y,2*radius,2*radius);
      line(x,y-radius,x,y);
      line(x,y,x+radius*cos(angle),y+radius*sin(angle));
      
      line(x+3,y-radius*2/3,x+radius+10,y-radius/3);
      text("Angle Increment",x+radius+15,y-radius/3);
      
    }
    
    void drawFunctionHelpGUI()
    {
      textFont(calibri);
      textSize(30);
      textAlign(LEFT, TOP);
      fill(0);
      float w = width/2+15;
      float q = w+10;
      
      text("Function Help",15,15);
      
      textFont(calibri25);
      textSize(25);
      text("Grid",15,55);
      text("Circle",15,190);
      text("Ellipse",15,325);
      text("Filled Circle",w,55);
      //text("Filled Ellipse",w,175);
      text("Line",w,175);
      text("Func",w,315);
      
      
      textFont(calibri14);
      textSize(14);
      
      text("Creates a grid of points.",15,85);
      text(fe[0],15,105);
      text("startx/starty - The (x,y) position of the top left corner of the grid",25,125);
      text("endx/endy - The (x,y) position of the bottom right corner of the grid",25,145);
      text("gapx/gapy - The gap between each point in the x and y directions",25,165);
      
      
      text("Creates a circle.",15,220);
      text(fe[1],15,240);
      text("centerx/centery - The (x,y) position of the center of the circle",25,260);
      text("radius - The radius of the circle from the center",25,280);
      text("angle increment - See \"Help\" button after going \"Back!\"",25,300);
      
      
      text("Creates an ellipse.",15,355);
      text(fe[2],15,375);
      text("center/centery/radius/angle_increment - See \"Circle\"",25,395);
      text("xmultiply/ymultiply - The amount the radius is streched by in the x/y direction",25,415);
      
      
      text("Creates a number of concentric circles.",w,85);
      text(fe[3],w,105);
      text("center/centery/radius/angle_increment - See \"Circle\"",q,125);
      text("gap - The difference in radius between each circle",q,145);
      
      
      /*text("Creates a number of concentric ellipses.",w,205);
      text(fe[4],w,225);
      text("center/centery/radius/xmultiply/ymultiply/angle_increment - See \"Ellipse\"",q,245);
      text("gap - The difference in unmultipled radius between each ellipse",q,265);*/
      
      
      text("Creates a straight line between two points.",w,205);
      text(fe[5],w,225);
      text("startx/starty - The (x,y) position of the start of the line",q,245);
      text("endx/endy - The (x,y) position of the end of the line",q,265);
      text("xgap - The difference between the x-coords between to consecutive points",q,285);
      
      
      text("Draws out a mathematical function in the form y = f(x).",w,345);
      text(fe[5],w,365);
      text("expression_in_x - An expression that uses x as variable",q,385);
      text("start/end_x_value - The x value range to apply the expression over",q,405);
      text("x_increment - The difference in x between two consecutive points",q,425);
      
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Callum Rogers

    Complex Number Transformer

    Add to Faves Me Likey@! 14
    You must login/register to add this sketch to your favorites.

    This is a system that graphically displays transformations in the complex plane. Read more at: http://en.wikipedia.org/wiki/Complex_plane

    Left click zooms in, right click zooms out and W,A,S,D and I,J,K,L move the axes. N adds numbers. Middle clicking does many things - see "Help" for more info.

    My personal favourites are:

    "func(300*sin(x/100), -5000, 5000, 2)" --> "x^11" (zoom out to 2.6E-26x)
    "filledCircle(0, 0, 300, 5, pi/64)" --> "(z+1)^2/(z-1)^2" (Joukoswki airfoil)

    Post your favourites in the comments and make sure to check the "Help" and "Examples" pages!

    Guigui plus+
    1 Oct 2009
    Impressive work!
    As I'm not accustom with the complex numbers, I tried some simple but haphazard functions. Anyway, I finally found out:
    "filledCircle(0,0,100,5,pi/512)"
    "pi(z*1.1)-pi^2" with a zoom factor of 4096x

    Only one thing: people on mac laptop can't do right click so we can't zoom out 8^(. An alternative shift+clic may solve this. I usually don't notice it but it's a pity we can't fully play with this wonderful sketch (of course, it's up to us to download your source code and make a modified standalone sketch).
    Callum Rogers
    1 Oct 2009
    Thanks for the feedback, Guigui, I've now updated it for mac users:

    Z/X will zoom in/out for the left graph.
    M/, will zoom in/ out for the right graph.

    Some more that I like:

    "grid(0,0,-300,-300,300,300,5,5)" --&gt; "z/(conj(z)+root(z,4,3))*root(z,4,1)"
    "func(300*sin(x/100), -5000, 5000, 2)" --&gt; "z^2.04" (splits the positive/negative sections)
    Xiaohan Zhang
    1 Oct 2009
    wow, this is great. it looks like you really spent a lot of time on this. I really like the function interpreter. I've been working on one myself for a while, and it's great to see a working version of it. One small thing is that "wasd" and "ijkl" move the graph in the opposite direction of what one would expect (W makes the graph go down).
    Callum Rogers
    1 Oct 2009
    I've changed the control system as you suggested - I was torn initially between making the actual shape move or just "moving the paper" it is on, but I think your way works better.

    As for the function interpreter, I started off with my own notation method which could do all the basic operations like +-*/^ with brackets as well but it was hard to make custom functions and, in any case, it was far to slow for thousands of points. Instead, I made use of the excellent JEP library which can be found at http://sourceforge.net/projects/jep/ .

    On a side note, it seems to be about 20-30x faster when exported rather than just pressing the "Run" button in Processing. I wonder why&gt;
    bejoscha
    25 Apr 2010
    Impressive sketch
    You need to login/register to comment.