JEphem Informatic Trail JEphem source code Curve.java
//*********************************************************************************
// class jephem.tools.Curve
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
package jephem.tools;

import jephem.astro.spacetime.SpaceConstants;
import jephem.GlobalVar;
import jephem.util.Debug;

import tig.GeneralConstants;
import tig.maths.Maths;
import tig.maths.Vector2;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
import java.io.*;

/******************************************************************************
Visual representation of curve plotting.
Used with {@link jephem.gui.CurveViewer}, which contains the controls surrounding a <CODE>Curve</CODE>.

@author Thierry Graff
@history may 10 2002 : creation.

@todo
*********************************************************************************/
public class Curve extends JPanel implements SpaceConstants, GeneralConstants{

  //=================================================================================
  //                                      INSTANCE VARIABLES
  //=================================================================================

  //***************** Data characteristics ******************
  /** The data to display. */
  private double[][] _data;
  /** Number of values to be represented for each curve. */
  private int _nbValues;
  /** Number of curves represented. */
  private int _nbCurves;
  /** min and max values in data coordinates. */
  private double _xMin, _xMax, _yMin, _yMax;

  //***************** Axis characteristics ******************
  /** Point were the axis intersect, in pixel coordinates.
  Define the vert. and hor. positions of the axis. */
  private Vector2 _axisCenter;
  /** Intervals for which the values are displayed on the axis. */
  private double _intervalX, _intervalY;
  /** Space taken by the axis for the display (in pixels). */
  private int _axisSpaceX, _axisSpaceY;

  //***************** Display area characteristics ******************
  /** Supplementary gaps between the axis and the border of the display area. */
  int _xGap, _yGap;
  /** height and width of the display area */
  int _h, _w;

  //=================================================================================
  //                               PRIVATE CONSTANTS
  //=================================================================================
  private final static BasicStroke STROKE = new BasicStroke(1.0f);
  private final static BasicStroke STROKE2 = new BasicStroke(2.0f);


  //=================================================================================
  //                            CONSTRUCTORS
  //=================================================================================
  /** Unique constructor. The base frame is set to equatorial frame. */
  public Curve(){
    super();
    try {
      this.setLayout(new BorderLayout());
      this.setBackground(Color.WHITE);
      calcHW();

      _xGap = 10;// to do : consider the case _w < _xGap
      _yGap = 10;// to do : consider the case _h < _yGap
      _axisSpaceX = 30;
      _axisSpaceY = 30;
    }
    catch(Exception e) {
      Debug.traceError(e);
    }
  }// end constructor

  //=================================================================================
  //                         PUBLIC METHODS
  //=================================================================================

  //*************** get / set data ***************
  /** Returns the data displayed by this curve.
  <BR>If the returned value is called 'data' :
  <BR><CODE>data[0]</CODE> contains the values of the X axis ;
  <BR><CODE>data[1]</CODE> contains the values of the first quantity on the Y axis ;
  <BR><CODE>data[2]</CODE> contains the values of the second quantity on the Y axis ;
  <BR>etc...
  */
  public double[][] getData(){ return _data; }

  /** Sets the data displayed by this curve.
  <BR>Meaning of parameter 'data' :
  <BR><CODE>data[0]</CODE> contains the values of the X axis ;
  <BR><CODE>data[1]</CODE> contains the values of the first quantity on the Y axis ;
  <BR><CODE>data[2]</CODE> contains the values of the second quantity on the Y axis ;
  <BR>etc...
  <BR>WARNING : the arrays <CODE>data[0]</CODE>, <CODE>data[1]</CODE> etc... must have the same length.
  */
  public void setData(double[][] data){
    // check length
    if(data.length < 2)
      throw new IllegalArgumentException("Incorrect len of parameter ' data' - Must have at least two lines");
    int len = data[0].length;
    for (int i = 0; i < data.length; i++) {
      if(data[i].length != len)
        throw new IllegalArgumentException("Incorrect len of parameter ' data' - see jephem.tools.Curve.setData() documentation");
    }
    _data = data;
    _nbValues = len; // all data[i] have the same length.
    _nbCurves = _data.length - 1;
//System.out.println("_nbValues = " + _nbValues);
//System.out.println("_nbCurves = " + _nbCurves);
    calcMinAndMax();
  }// end setData

  //*****************************************************************************
  //****************************** paintComponent *******************************
  //*****************************************************************************
  /** Paints the curve on its display area. */
  public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    calcHW();
    _axisCenter = new Vector2(_xGap + (double)_axisSpaceX/2, _h - (_yGap + (double)_axisSpaceY/2));

    g2.setStroke(STROKE);
    drawAxis(g2);

    // Draw the curves
    g2.setStroke(STROKE2);
    g2.setPaint(Color.BLACK);
    Vector2 v0D, v1D, v0P, v1P; // P and D for Pixel and Data coordinates
    for(int i = 1; i <= _nbCurves; i++){
      v0D = new Vector2(_data[0][0], _data[i][0]); // first point to draw
      for(int j = 0; j < _nbValues - 1; j++){
        v1D = new Vector2(_data[0][j+1], _data[i][j+1]); // second point to draw
        // change to pixel coords
        v0P = dataToPixel(v0D);
        v1P = dataToPixel(v1D);
        g2.draw(new Line2D.Double((int)v0P.x0, (int)v0P.x1, (int)v1P.x0, (int)v1P.x1));
        // v0D takes the value of v1D
        v0D = v1D;
      }// end for j
    }// end for i

  }// end paintComponent

  //=================================================================================
  //                                      PRIVATE METHODS
  //=================================================================================

  //********************** pixelToData **********************
  /** Converts pixel coordinates to data coordinates. */
  private Vector2 pixelToData(Vector2 vP){
    // Formulae found from dataToPixel()
    double a, b;
    // conversion for x
    a = (_xMax - _xMin)/((double)_w - 2*(double)_xGap);
    b = -((double)_xGap*(_xMax + _xMin) - (double)_w*_xMin)/((double)_w - 2*(double)_xGap);
    double xD = a*vP.x0 + b;
    // conversion for y
    a = (_yMin - _yMax)/((double)_h - 2*(double)_yGap);
    b = -((double)_yGap*(_yMax + _yMin) - (double)_h*_yMax)/((double)_h - 2*(double)_yGap);
    double yD = a*vP.x1 + b;
    return new Vector2(xD, yD);
  }// end pixelToData

  //********************** dataToPixel **********************
  /** Converts data coordinates to pixel coordinates. */
  private Vector2 dataToPixel(Vector2 vD){
    double a, b;
    // conversion for x
    a = ((double)_w - 2*(double)_xGap)/(_xMax - _xMin);
    b = ((double)_xGap*(_xMax + _xMin) - (double)_w*_xMin)/(_xMax - _xMin);
    double xP = a*vD.x0 + b;
    // conversion for y
    a = ((double)_h - 2*(double)_yGap)/(_yMin - _yMax);
    b = ((double)_yGap*(_yMax + _yMin) - (double)_h*_yMax)/(_yMin - _yMax);
    double yP = a*vD.x1 + b;
    return new Vector2(xP, yP);
  }// end dataToPixel

  //********************** calcMinAndMax **********************
  /** Computes from _data the min and max values to display on the x and y axis.
  @post _xMin, _xMax, _yMin, _yMax are computed.
  */
  private void calcMinAndMax(){
    _xMin = Maths.min(_data[0]);
    _xMax = Maths.max(_data[0]);

    _yMin = Maths.min(_data[1]);
    _yMax = Maths.max(_data[1]);
    double yMin, yMax;
    for (int i = 2; i <= _nbCurves; i++) {
      yMin = Maths.min(_data[i]);
      yMax = Maths.max(_data[i]);
      if(yMin < _yMin) _yMin = yMin;
      if(yMax > _yMax) _yMax = yMax
      ;
    }
//System.out.println("_xMin = " + _xMin);
//System.out.println("_xMax = " + _xMax);
//System.out.println("_yMin = " + _yMin);
//System.out.println("_yMax = " + _yMax);
  }// end calcMinAndMax

  //*************** calcRHW ***************
  /** Computes the height and width of the panel. */
  private void calcHW(){
    // height, width of the panel
    _w = this.getSize().width;
    _h = this.getSize().height;
  }// end calcHW

  //*************** drawAxis ***************
  /** Computes the height and width of the panel. */
  private void drawAxis(Graphics2D g2){
    int posX = (int)_axisCenter.x0;
    int posY = (int)_axisCenter.x1;
//System.out.println("posX = " + posX + " posY = " + posY);
    g2.draw(new Line2D.Double(_xGap, posY, _w - _xGap, posY)); // X axis
    g2.draw(new Line2D.Double(posX, _h - _yGap, posX, _yGap)); // Y axis

  }// end drawAxis

}// end class SkyMap