Package

Source Code of GraphPanel$Line

import java.awt.*;
import java.awt.event.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.tree.*;

import ket.*;
import ket.Calculate;
import ket.display.ColourScheme;
import ket.display.ColourSchemeDecorator;
import ket.math.*;
import ket.math.convert.Like;
import ket.math.purpose.DoubleValue;
import ket.math.purpose.NumberValue;
import ket.math.purpose.Word;
import ketUI.Document;
import ketUI.DocumentManager;
import ketUI.panel.KetPanel;

public class GraphPanel
  extends JPanel
  implements KeyListener, MouseMotionListener, MouseListener, MouseWheelListener {

  static final double delta = Math.PI/36.0; // rad
  double alpha = 0.0;
  double beta = 0.0;
  double gamma = 0.0;

  int u0, v0;

  Vector<Line> lines;
  Document document;
  double minX, maxX;
  double minY, maxY;

  public class Line {
    public final Vector<Double> dataX;
    public final Vector<Double> dataY;
    public final Vector<Double> dataZ;
    public Line() {
      dataX = new Vector<Double>();
      dataY = new Vector<Double>();
      dataZ = new Vector<Double>();
    }
    public double[] get(int i) {
      return new double[]{dataX.get(i), dataY.get(i), dataZ.get(i)};
    }
  }

  public GraphPanel(Document document) {
    this.document = document;
    setFocusable(true);
    addKeyListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
    addMouseWheelListener(this);
    lines = new Vector<Line>();
    lines.add(new Line()); //?
    reset();
    calc();
  }

  public void reset() {
    minX = -10.0;
    maxX = 10.0;
    minY = -10.0;
    maxY = 10.0;
    alpha = 0.0;
    beta = 0.0;
    gamma = 0.0;
  }

  public Vector<Equation> getEquations() {
    return document.getEquationList().getEquations();
  }

  public void calc() {
    lines.clear();
    Word horizontal = new Word("x");
    Word time = new Word("t");
    for (Equation e : getEquations()) {
      Argument root = e.getRoot();
      Set<Token> variables = root.getVariables();
      if (hasOnly(variables, horizontal)) {
        // i.e. A simple plot, f(x).
        Token target = new Token(horizontal);
        Line l = new Line();
        double step = (maxX-minX)/2.0/getWidth();
        double dx = maxX - minX; // Include extra to handle mouse drags.
        for (double x=minX - dx; x<=maxX+dx; x+=step) {
          l.dataX.add(x);
          l.dataY.add(Calculate.eval(root, x, target));
          l.dataZ.add(0.0);
        }
        lines.add(l);
      } else if (hasOnly(variables, time) && Like.hasForm(root, Function.VECTOR, 2)) {
        // i.e. An xy-plot [x(t), y(t)].
        Argument x = root.asBranch().firstChild();
        Argument y = root.asBranch().lastChild();
        Token target = new Token(time);
        Line l = new Line();
        double step = 1.0 / 500.0;
        for (double t=0.0; t<1.0; t+=step) {
          l.dataX.add(Calculate.eval(x, t, target) );
          l.dataY.add(Calculate.eval(y, t, target));
          l.dataZ.add(0.0);
        }
        lines.add(l);
      } else if (hasOnly(variables, time) && Like.hasForm(root, Function.VECTOR, 3)) {
        // i.e. An xy-plot [x(t), y(t), z(t)].
        Argument x = root.asBranch().getChild(0);
        Argument y = root.asBranch().getChild(1);
        Argument z = root.asBranch().getChild(2);
        Token target = new Token(time);
        Line l = new Line();
        double step = 1.0 / 500.0;
        for (double t=0.0; t<1.0; t+=step) {
          l.dataX.add(Calculate.eval(x, t, target) );
          l.dataY.add(Calculate.eval(y, t, target));
          l.dataZ.add((Calculate.eval(z, t, target)));
        }
        lines.add(l);
      }
    }
    repaint();
  }

  public boolean hasOnly(Set<Token> variables, Word word) {
    if (variables.size()!=1) {
      return false;
    }
    Iterator<Token> iterator = variables.iterator();
    return iterator.next().getState().equals(word);
  }

  public void setupAntialiasing(Graphics2D g2D) {
    g2D.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2D.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2D.setRenderingHint(
        RenderingHints.KEY_FRACTIONALMETRICS,
        RenderingHints.VALUE_FRACTIONALMETRICS_ON);
  }

  /*
   * Five point fininte difference formula.
   * */
  public double dash(double Fhm2, double Fhm1, double Fh, double Fhp1, double Fhp2, double h) {
    // TODO: Use this to filter or over-sample graphs to maximize dv/du variations.
    return (-Fhp2 + 8.0*Fhp1 - 8.0*Fhm1 + Fhm2) / 12.0 / h;
  }

  public int getU(double x) {
    return (int) ((x-minX) * width() / (maxX-minX));
  }
  public int getV(double y) {
    return (int) height() - (int) ((y-minY)*height()/(maxY-minY));
  }

  public double getU(double[] mu, double[] v) {
    return getU(dot(mu, v));
  }

  public double getV(double[] nu, double[] v) {
    return getV(dot(nu, v));
  }

  public double getX(double u) {
    return u*(maxX - minX)/getWidth() + minX;
  }
  public double getY(double v) {
    return v*(maxY - minY)/getHeight() + minY;
  }

  public double[] rotate(double[] t) {
    // rot z
    double[] u = new double[]{
      Math.cos(alpha)*t[0]-Math.sin(alpha)*t[1],
      Math.sin(alpha)*t[0]+Math.cos(alpha)*t[1],
      t[2]};
    // rot x
    double[] v = new double[]{
      u[0],
      Math.cos(beta)*u[1]-Math.sin(beta)*u[2],
      Math.cos(beta)*u[2]+Math.sin(beta)*u[1]};
    // rot z
    double[] w = new double[]{
      Math.cos(gamma)*v[0]-Math.sin(gamma)*v[1],
      Math.sin(gamma)*v[0]+Math.cos(gamma)*v[1],
      v[2]};
    return w;
  }

  public double dot(double[] a, double[] b) {
    double sum = 0.0;
    sum += a[0]*b[0];
    sum += a[1]*b[1];
    sum += a[2]*b[2];
    return sum;
  }

  public double width() {
    return this.getWidth()-1;
  }

  public double height() {
    return this.getHeight()-1;
  }

  public void paint(Graphics g) {
    Graphics2D g2D = (Graphics2D) g;
    setupAntialiasing(g2D);

    ColourSchemeDecorator colourScheme = document.getColourScheme();
    Color backgroundColour = colourScheme.getBackgroundColour();
    Color argColour = colourScheme.getArgColour(0);
    Color borderColour = colourScheme.getBorderColour();

    // (Don't cut the last pixel off).
    g2D.setColor(backgroundColour);
    g2D.fillRect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);

    double[] mu = rotate(new double[]{1.0, 0.0, 0.0});
    double[] nu = rotate(new double[]{0.0, 1.0, 0.0});

    int c=0;
    for (Line l : lines) {
      Double oldU = null;
      Double oldV = null;
      for (int i=0; i<l.dataX.size(); i++) {
        double u = getU(mu, l.get(i));
        double v = getV(nu, l.get(i));
        float hue = c * 1.0f / lines.size();
        int rgb = Color.HSBtoRGB(hue, 1.0f, 1.0f);
        g2D.setColor(new Color(rgb));

        if (oldU!=null && oldV!=null) {
          g2D.draw(new Line2D.Double(oldU, oldV, u, v));
        }
        oldU = u;
        oldV = v;
      }
      c += 1;
    }

    g2D.setColor(borderColour);

    double xNegX = getU(mu, new double[]{-1.0, 0.0, 0.0});
    double xNegY = getV(nu, new double[]{-1.0, 0.0, 0.0});
    double xPosX = getU(mu, new double[]{+1.0, 0.0, 0.0});
    double xPosY = getV(nu, new double[]{+1.0, 0.0, 0.0});

    double yNegX = getU(mu, new double[]{0.0, -1.0, 0.0});
    double yNegY = getV(nu, new double[]{0.0, -1.0, 0.0});
    double yPosX = getU(mu, new double[]{0.0, +1.0, 0.0});
    double yPosY = getV(nu, new double[]{0.0, +1.0, 0.0});

    double zNegX = getU(mu, new double[]{0.0, 0.0, -1.0});
    double zNegY = getV(nu, new double[]{0.0, 0.0, -1.0});
    double zPosX = getU(mu, new double[]{0.0, 0.0, +1.0});
    double zPosY = getV(nu, new double[]{0.0, 0.0, +1.0});

    double axisX = maxAbs(xPosX-xNegX, yPosX-yNegX, zPosX-zNegX);
    double axisY = maxAbs(xPosY-xNegY, yPosY-yNegY, zPosY-zNegY);

    double scaleX = width() / axisX;
    double scaleY = height() / axisY;

    double scale = 0.90 * Math.min(scaleX, scaleY);

    // int exponent = (int) Math.ceil(Math.log10(scale)) - 1;
    //D System.out.println(exponent);


    g2D.draw(new Line2D.Double(
      getU(mu, vscale(new double[]{-1.0, 0.0, 0.0}, scale)),
      getV(nu, vscale(new double[]{-1.0, 0.0, 0.0}, scale)),
      getU(mu, vscale(new double[]{+1.0, 0.0, 0.0}, scale)),
      getV(nu, vscale(new double[]{+1.0, 0.0, 0.0}, scale))));

    g2D.draw(new Line2D.Double(
      getU(mu, vscale(new double[]{0.0, -1.0, 0.0}, scale)),
      getV(nu, vscale(new double[]{0.0, -1.0, 0.0}, scale)),
      getU(mu, vscale(new double[]{0.0, +1.0, 0.0}, scale)),
      getV(nu, vscale(new double[]{0.0, +1.0, 0.0}, scale))));

    g2D.draw(new Line2D.Double(
      getU(mu, vscale(new double[]{0.0, 0.0, -1.0}, scale)),
      getV(nu, vscale(new double[]{0.0, 0.0, -1.0}, scale)),
      getU(mu, vscale(new double[]{0.0, 0.0, +1.0}, scale)),
      getV(nu, vscale(new double[]{0.0, 0.0, +1.0}, scale))));

  }

  public double[] vscale(double[] v, double scale) {
    return new double[]{scale*v[0], scale*v[1], scale*v[2]};
  }

  public double maxAbs(double a, double b, double c) {
    if (a*a>b*b) {
      if (a*a>c*c) {
        return Math.abs(a);
      } else {
        return Math.abs(c);
      }
    } else {
      return Math.abs(b);
    }
  }

  public void moveIn() {
    double dx = maxX - minX;
    double dy = maxY - minY;
    minX += dx/4;
    maxX -= dx/4;
    minY += dy/4;
    maxY -= dy/4;
    calc();
  }

  public void moveOut() {
    double dx = maxX - minX;
    double dy = maxY - minY;
    minX -= dx/4;
    maxX += dx/4;
    minY -= dy/4;
    maxY += dy/4;
    calc();
  }

  public void moveLeft() {
    double dx = maxX - minX;
    minX -= dx/10;
    maxX -= dx/10;
    calc();
  }

  public void moveRight() {
    double dx = maxX - minX;
    minX += dx/10;
    maxX += dx/10;
    calc();
  }

  public void moveUp() {
    double dy = maxY - minY;
    minY += dy/10;
    maxY += dy/10;
    calc();
  }

  public void moveDown() {
    double dy = maxY - minY;
    minY -= dy/10;
    maxY -= dy/10;
    calc();
  }

  @Override
  public void keyPressed(KeyEvent keyEvent) {
    char c = keyEvent.getKeyChar();
    switch (keyEvent.getKeyCode()) {
      case KeyEvent.VK_LEFT:    moveLeft()return;
      case KeyEvent.VK_RIGHT:   moveRight(); return;
      case KeyEvent.VK_UP:      moveUp();    return;
      case KeyEvent.VK_DOWN:    moveDown()return;
      case KeyEvent.VK_SPACE:   moveOut();   return;
    }
    switch (c) {
      case 'L':
        alpha += delta; calc();   return;
      case 'H':
        alpha -= delta; calc();   return;
      case 'O':
        beta += delta;  calc();   return;
      case 'I':
        beta -= delta;  calc();   return;
      case 'K':
        gamma += delta; calc();   return;
      case 'J':
        gamma -= delta; calc();   return;

      case '-':
      case ' ': moveOut();                return;
                                                          
      case '+':                         
      case 'i': moveIn();                 return;                        
      case 'o': moveOut();                return;
                                                          
      case '0': reset(); calc();         return;
      case 'k': moveUp();                return;
      case 'j': moveDown();              return;
      case 'h': moveLeft();              return;
      case 'l': moveRight();             return;
    }
  }

  @Override public void keyReleased(KeyEvent keyEvent) { }
  @Override public void keyTyped(KeyEvent keyEvent) { }
  @Override public void mouseClicked(MouseEvent e) {
    /*
    boolean leftButton = e.getButton()==MouseEvent.BUTTON1;
    boolean singleClick = e.getClickCount()==1;
    if (leftButton) {
      moveIn();
    } else {
      moveOut();
    }
    */
  }
  @Override public void mouseExited(MouseEvent e) { }
  @Override public void mouseEntered(MouseEvent e) { }
  @Override public void mouseMoved(MouseEvent e) { }

  @Override
  public void mouseReleased(MouseEvent e) {
    // What is the difference?
    requestFocusInWindow();
    calc();
  }

  @Override
  public void mousePressed(MouseEvent e) {
    requestFocusInWindow();
    u0 = e.getX();
    v0 = e.getY();
  }

  @Override
  public void mouseDragged(MouseEvent e) { // TODO: Right mouse drag rotates view.
    int u1 = e.getX();
    int v1 = e.getY();
    double dx = getX(u1) - getX(u0);
    double dy = getY(v1) - getY(v0);
    minX -= dx;
    maxX -= dx;
    minY += dy; // Negative height?
    maxY += dy;
    repaint();

    u0 = u1;
    v0 = v1;
  }

  @Override
  public void mouseWheelMoved(MouseWheelEvent e) {
    int rotation = e.getWheelRotation();
    if (rotation>0) {
      moveOut();
    } else {
      moveIn();
    }
    repaint();
  }
}
TOP

Related Classes of GraphPanel$Line

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.