JEphem Informatic Trail JEphem source code SkyMapBase.java
//*********************************************************************************
// class jephem.tools.SkyMapBase
// 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.sky.BSC5;
import jephem.astro.sky.Constellations;
import jephem.astro.sky.ConstellationConstants;
import jephem.astro.spacetime.SpaceConstants;
import jephem.astro.solarsystem.SolarSystemConstants;
import jephem.GlobalVar; // only used to retrieve BSC5 directory
import jephem.util.Debug;

import tig.GeneralConstants;
import tig.maths.Maths;
import tig.maths.Matrix3;
import tig.maths.Vector3;

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

/******************************************************************************
Contains the geometrical functionalities of a sky map ; do not use this class directly,
use instead {@link SkyMap}.
@author Thierry Graff
@history may 09 2002 : creation from SkyMap

@todo when rotation, center of rotation must be the center of the screen.
*********************************************************************************/
public class SkyMapBase extends JPanel implements ConstellationConstants, SpaceConstants, GeneralConstants{

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

  /** base frame. */
  private int _skyFrame;

  /** zoom factor. */
  private double _zoom;

  /** Eye matrix. */
  private Matrix3 _em;

  /** Eye orientation. */
  double _theta0, _phi0;

  // Global geometric characteristics
  int _h, _w; // height, width of this panel
  /** Radius of the map, depending on the zoom factor. */
  int _r;

  //=================================================================================
  //                               PUBLIC CONSTANTS
  //=================================================================================

  // Orientation constants
  /** Constant to indicate X axis. */
  public static final int X = 0;
  /** Constant to indicate Y axis. */
  public static final int Y = 1;
  /** Constant to indicate Z axis. */
  public static final int Z = 2;
  /** Constant to indicate direct sens of rotation (anti-clockwise). */
  public static final int PLUS = 3;
  /** Constant to indicate indirect sens of rotation (clockwise). */
  public static final int MINUS = 4;


  //=================================================================================
  //                            CONSTRUCTORS
  //=================================================================================
  /** Unique constructor. The base frame is set to equatorial frame. */
  public SkyMapBase(){
    super();
    try {
      this._zoom = 1;
      this._skyFrame = FRAME_EQUATORIAL;
      _em = Matrix3.getIdentityMatrix();// at the beginning, eye matrix is the identity matrix
rotateEye(X, -90);
_theta0 = 0;
_phi0 = 0;
    }
    catch(Exception e) {
      Debug.traceError(e);
    }
  }// end constructor

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

  //*************** get / set eye matrix ***************
  /** Returns the eye matrix, used to define the viewer's orientation. */
  public Matrix3 getEyeMatrix(){ return _em; }
  /** Sets the eye matrix, used to define the viewer's orientation. */
  public void setEyeMatrix(Matrix3 em){ _em = em; } // also repaint ???

  //*************** get / set zoom ***************
  /** Returns the zoom of this sky map. */
  public double getZoom(){ return _zoom; }
  /** Sets the zoom of this sky map, and repaints. */
  public void setZoom(double zoom){
    _zoom = zoom;
    this.repaint();
  }// end setZoom

  //*************** rotateEye ***************
  /** Changes the orientation of the viewer's eye and repaints.
  @param direction Use constants of this class to expree it.
  @param increment The value of the rotation angle, <B>in degres</B>.
  */
  public void rotateEye(int direction, double increment){

    Matrix3 rot;
    increment = Math.toRadians(increment);
    switch(direction){
      case X : // up / down
        rot = Matrix3.getRotX(increment); break;
      case Y : // right / left
        rot = Matrix3.getRotY(increment); break;
      case Z : // anti-clockwise / clockwise
        rot = Matrix3.getRotZ(increment); break;
      default:
        throw new IllegalArgumentException("invalid 'direction' parameter");
    }
    // modify the eye matrix :
    _em = Matrix3.mul(rot, _em);
    this.repaint();
  }// end rotateEye

  //*************** setEyeOrientation ***************
  /** Sets the orientation of the viewer's eye and repaints.
  <BR>The parameters designate the direction to which the eye should look ;
  they are expressed in degrees, in sky coordinates.
  */
  public void setEyeOrientation(double theta, double phi){
    _theta0 = Math.toRadians(theta);
    _phi0 = Math.toRadians(phi);
    this.repaint();
  }// end setEyeOrientation

  //*************** drawCircle ***************
  /** Draws a circle on the given Graphics2D, taking into account the eye matrix.
  <BR>The angles specify the circle orientation :
  <BR><IMG SRC="doc-files/drawCircle.jpg" ALT="" HEIGHT="312" BORDER="0">
  @param alpha0 <B>in degrees</B>.
  @param epsilon0 <B>in degrees</B>.
  @param delta0 <B>in degrees</B>.
  */
  public void drawCircle(Graphics2D g2, double alpha0, double epsilon0, double delta0){
    alpha0 = Math.toRadians(alpha0);
    epsilon0 = Math.toRadians(epsilon0);
    delta0 = Math.toRadians(delta0);

    double step = Math.toRadians(10); // step used to draw a circle
    int nbIterations = (int)Math.floor(2*Math.PI/step);
    double alpha = 0;
    Vector3 v0, v1, v0P, v1P;
    double x0, y0, x1, y1;
    for(int i = 0; i < nbIterations; i++){
      v0 = getCartesianCoords(alpha + epsilon0, delta0);// The equation of the circle in R1 is : delta = delta0
      // convert v0 in the sky frame by two rotations
      v0 = Vector3.mul(Matrix3.getRotX(-epsilon0), v0);
      v0 = Vector3.mul(Matrix3.getRotZ(-alpha0), v0);
      v0 = Vector3.mul(_em, v0); // convert v0 in the eye frame
      v0P = screenToPixel(v0);// Transform to pixel coordinates

      alpha+= step; // Increment alpha

      // perform the same operations for v1
      v1 = getCartesianCoords(alpha + epsilon0, delta0);
      v1 = Vector3.mul(Matrix3.getRotX(-epsilon0), v1);
      v1 = Vector3.mul(Matrix3.getRotZ(-alpha0), v1);
      v1 = Vector3.mul(_em, v1);
      v1P = screenToPixel(v1);// Transform to pixel coordinates

      if(v0.x2 > 0 && v1.x2 > 0){
        g2.draw(new Line2D.Double((int)v0P.x0, (int)v0P.x1, (int)v1P.x0, (int)v1P.x1));
      }
    }// end for i

  }// end drawCircle

  //=================================================================================
  //                                      PROTECTED METHODS
  //=================================================================================

  //*************** calcRHW ***************
  /** Computes the height, width of the panel, and the radius of the circle containing the chart,
  in pixels ; stores these data in instance variables.
  <BR>Written to avoid computing these values several times.
  */
  void calcRHW(){
    // height, width of the panel
    _w = this.getSize().width;
    _h = this.getSize().height;
    int m = 0; // margin
    int r0 = Math.min(_h/2 - 2*m, _w/2 - 2*m); // r0 = radius of the disk (in pixels) when _zoom = 1.
    if(r0 < 0) r0 = 0;
    _r = (int)_zoom*r0; // r = radius of the black disk, in pixels.
  }// end calcRHW


  //********************************************************************************
  //                         Coordinate transformations
  //********************************************************************************

  //*************** getCartesianCoords ***************
  /** Computes cartesian coordinates assuming that 'theta' and 'phi' are in radians, and that rho = 1.*/
  Vector3 getCartesianCoords(double theta, double phi){
//    theta = theta - Math.toRadians(_theta0);
//    phi = phi - Math.PI/2 - Math.toRadians(_phi0);
    return new Vector3( Math.cos(phi)*Math.cos(theta),
                         Math.cos(phi)*Math.sin(theta),
                         Math.sin(phi)
                       );
  }// end getCartesianCoords

  //*************** getSphericalCoords ***************
  /** Computes spherical coordinates of a vector.*/
  Vector3 getSphericalCoords(Vector3 v){
    return new Vector3( 1,
                        Maths.atan3(v.x1, v.x0),
                        Math.asin(v.x2/Vector3.norm(v))
                       );
  }// end getSphericalCoords

  //*************** skyToEye ***************
  /** Transforms sky coordinates to eye coordinates.
  Transformation done between cartesian coordinates.
  */
  Vector3 skyToEye(Vector3 vC){
    return Vector3.mul(_em, vC);
  }// end skyToEye

  //*************** eyeToSky ***************
  /** Transforms eye coordinates to sky coordinates.
  Transformation done between cartesian coordinates.
  */
  Vector3 eyeToSky(Vector3 vE){
    return Vector3.mul(Matrix3.invert(_em), vE);
  }// end eyeToSky

  //*************** screenToEye ***************
  /** Transforms screen coordinates to eye coordinates.
  @param vS a vector containing screen <B>cartesian</B> coordinates.
  @return a vector containing <B>spherical</B> coordinates.
  */
  Vector3 screenToEye(Vector3 vS){
    return new Vector3( Maths.atan3(vS.x0, vS.x1),
                        Math.acos(Vector3.norm(vS)),
                        0);
  }// end screenToEye

  //*************** eyeToScreen ***************
  /** Transforms eye coordinates to screen coordinates (implements the projection). */
  // NOT implemented, useless for orthogonal projection.
//  Vector3 eyeToScreen(Vector3 vE){
//  }// end eyeToScreen


  //*************** screenToPixel ***************
  /** Transforms screen coordinates to pixel coordinates.
  <BR>Assumes that <CODE>calcRHW()</CODE> was called before.
  */
  Vector3 screenToPixel(Vector3 vS){
    return new Vector3( -vS.x0*_r + _w/2,
                        -vS.x1*_r + _h/2,
                        0);
  }// end screenToPixel

  //*************** pixelToScreen ***************
  /** Transforms pixel coordinates to screen coordinates.
  <BR>Assumes that <CODE>calcRHW()</CODE> was called before.
  */
  Vector3 pixelToScreen(Vector3 vP){
    return new Vector3( (-vP.x0 + (double)_w/2)/(double)_r,
                        (-vP.x1 + (double)_h/2)/(double)_r,
                        0);
  }// end pixelToScreen

}// end class SkyMap