简体   繁体   中英

Java Simple Grapher Applet

I'm trying to make a simple function drawer in Java. I'm using the ScriptEngine API to parse the equation from a string, but it gets very slow while drawing. Is there another way to do the same thing? Here is the code:

private String v;
@Override
public void init(){
    setSize(600,600);
    v = JOptionPane.showInputDialog("Input function:");
}
@Override
public void paint(Graphics g){
    drawQuadrants(g);
    drawEquation(g);
}
private void drawEquation(Graphics g) {
    g.setColor(Color.BLUE);
    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine engine = mgr.getEngineByName("JavaScript");
    v = v.replace("sin", "Math.sin")
    .replace("cos", "Math.cos")
    .replace("sen", "Math.sin")
    .replace("tan", "Math.tan")
    .replace("tg", "Math.tan")
    .replace("log", "Math.log")
    .replace("Log(x)","(Math.log(x)/Math.LN10)");
    for(double x0 = -10;x0<=10;x0+=0.001){
        engine.put("x", x0);
        try {
            double y0 = (Double)engine.eval(v);
            drawPoint(g,x0,-y0);
        } catch (HeadlessException | ScriptException e) {
            e.printStackTrace();
        }
    }
}
private void drawQuadrants(Graphics g) {
    g.setColor(Color.BLACK);
    g.drawLine(0, 300, 600, 300);
    g.drawLine(300, 0, 300, 600);
    g.setFont(new Font("Arial",Font.BOLD,15));
    g.drawString("x", 580, 320);
    g.drawString("y", 280, 20);
    for(int l = 0;l<=600;l+=30){
        g.drawLine(l, 297, l, 303);
    }
    for(int l = 0;l<=600;l+=30){
        g.drawLine(297, l, 303, l);
    }
}
private void drawPoint(Graphics g, double x0, double y0) {
    int newx0 = (int)map((float)x0, (float)-10, (float)10, (float)0.0, (float)600.0);
    int newy0 = (int)map((float)y0, (float)-10, (float)10, (float)0.0, (float)600.0);
    g.drawOval(newx0, newy0, 1, 1);
}
public static final float map(float value, float start1, float stop1, float start2, float stop2)
{
    return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
}

Well you could always try my code,it is simple fast and elegant.It can also plot any graph by using an external parser.

    import javax.swing.*;
    import java.awt.*;
     import java.util.Scanner;
       import net.objecthunter.exp4j.*;

     class math extends JFrame
     {
       public static void main(String args[])
      {
    math m=new math();
    m.setVisible(true);
    m.setLocationRelativeTo(null);


}

public void paintallies(Graphics G1,double sf)
{int i;
 Graphics2D g21=(Graphics2D) G1;
 g21.setColor(Color.GREEN);
    for(i=0;i<=600;i=(int) (i+sf))
    {
        g21.drawLine(i,0,i,600);
        g21.drawLine(0,i,600,i);

    }

}
public void paintaxes(Graphics G1)
{
    Graphics2D g21=(Graphics2D) G1;
    g21.setColor(Color.BLACK);
    g21.drawLine(300,0,300,600);//y axis

    g21.drawLine(0,300,600,300); //x axis

}


public void paint(Graphics G)
{
    int i;
    double j,k;

    Scanner s=new Scanner(System.in);
    System.out.println("Enter input");
    String input=s.nextLine();
    System.out.println("Enter scale factor");
    double sf=s.nextDouble();
    double sff=300/sf;
    double kf=sff;
    double count=0;






    Graphics g2=(Graphics) G;
    paintallies(G,sf);
    paintaxes(G);

    g2.translate(300,300);
    do
    {
        kf=kf-(1/sf);
        count++;

    }while(kf>=0);
    double counts=2*count;


    Color c=Color.RED;
    g2.setColor(c.darker());

    double yarr[]=new double[(int)counts];
    double xarr[]=new double[(int)counts];



    Expression E=new ExpressionBuilder(input).variables("x").build();


     j=-sff; k=-sff;
    for(i=0;i<counts;i++)
    {

        xarr[i]=j;
        j=j+(1/sf);


        E.setVariable("x",k);
        yarr[i]=E.evaluate();
        k=k+(1/sf);

        xarr[i]=sf*xarr[i];
        yarr[i]=-sf*yarr[i];

    }

    for(i=0;i<counts;i++)
    {
        if(i==counts-1)
        {
            break;
        }
        else
        {
        g2.drawLine((int)xarr[i],(int)yarr[i],(int)xarr[i+1],(int)yarr[i+1]);

        }
    }


}






math()
{
    super("Grapher");
    setSize(600,600);
    setResizable(true);



}

}

One low-hanging fruit may be to increase the value in the for-loop step in the drawEquation() method. When choosing this value, take into consideration that you have ~ 2K to 3K pixels max horizontally. Yet, you're iterating over 20K points on the X axis. Try x0+=0.01 first, then adjust as needed. This may cause your program to run in 1/10th the time.

It would be much faster if you - make ScriptEngineManager mgr object as member variable and create it once (in constructor of your class)

  • invoke parsing and calcuations from drawEquation only when text in input dialog changes, not in every draw. You could save computed values in two arrays (one array for x, another one for y values).

As general rule (for every graphic engime I do know), onDraw method should be small and fast.

  • do not perform object cration and initalization in onDraw. That crates A LOT of work for garbage collector.
  • do not perform extensive computation in onDraw, if those computation may be performed before.

EDIT: Calculate and draw only points you need to draw. You need to know width of your Graphic objects, compute increment value of the for loop and have only g.width() number of iterations. More iterations is just a waste- you are drawing many points in the same screen location.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM