/**
  * Create user interface
  *
  * @return
  */
 private void updateElevation() {
   double my_h = h;
   if (my_h == Double.MAX_VALUE)
     h = my_h = globe == null ? 0 : globe.getElevation(lon, lat) * globe.getElevationScale();
   if (Math.abs(hTerrain + my_h - hEllps) > 0.01) {
     hTerrain = hEllps - my_h;
     if (hTerrain < min_h) {
       hTerrain = min_h;
       hEllps = hTerrain + my_h;
     }
     ele_changed = true;
   }
 }
  public Point3d getEye(Point3d eye) {
    if (eye == null) eye = new Point3d();
    if (globe != null) globe.getEllipsoid().toCartesian(lat, lon, hEllps, eye);
    else eye.set(0, 0, 0);

    return eye;
  }
 /** Move left/right a given distance. */
 public void translateSideway(double d) {
   if (globe == null || d == 0) return;
   lla = globe.getEllipsoid().forwGeodesic(lat, lon, -d, az + Math.PI / 2., lla);
   lat = lla.lat;
   lon = lla.lon;
   az = Ellipsoid.adjlonPos(lla.az + Math.PI / 2.);
   lat_changed = lon_changed = az_changed = true;
   h = Double.MAX_VALUE;
 }
  /** Move up/down a given distance. */
  public void translateUpDown(double d) {
    if (globe == null || d == 0) return;
    double hDist = d * Math.cos(Math.PI / 2. + ha);
    double vDist = d * Math.sin(Math.PI / 2. + ha);

    lla = globe.getEllipsoid().forwGeodesic(lat, lon, hDist, az, lla);
    lat = lla.lat;
    lon = lla.lon;
    az = Ellipsoid.adjlonPos(lla.az + Math.PI);
    hEllps += vDist;
    ele_changed = lat_changed = lon_changed = az_changed = true;
    h = Double.MAX_VALUE;
  }
  public void rotateAroundPointer(double x_rot, double y_rot) {
    if (hTerrain < 0) hTerrain = 0;
    if (Math.abs(point_dist * Math.sin(x_rot)) > hTerrain / 10)
      x_rot = Math.asin(hTerrain / point_dist / 10) * (x_rot >= 0 ? 1 : -1);
    if (Math.abs(point_dist * Math.sin(y_rot)) > hTerrain / 10)
      y_rot = Math.asin(hTerrain / point_dist / 10) * (y_rot >= 0 ? 1 : -1);

    // translateSideway(dist*Math.sin(x_rot))
    double d_x = point_dist * Math.sin(x_rot);
    lla = globe.getEllipsoid().forwGeodesic(lat, lon, -d_x * Math.cos(ha), az + Math.PI / 2., lla);
    lat = lla.lat;
    lon = lla.lon;
    az = Ellipsoid.adjlonPos(lla.az + Math.PI / 2.);

    // translateUpDown(dist*Math.sin(y_rot));
    double d_y = point_dist * Math.sin(y_rot);
    hEllps += d_y * Math.sin(Math.PI / 2. + ha);
    lla = globe.getEllipsoid().forwGeodesic(lat, lon, d_y * Math.cos(Math.PI / 2. + ha), az, lla);
    lat = lla.lat;
    lon = lla.lon;
    az = Ellipsoid.adjlonPos(lla.az + Math.PI);

    // translateForward(dist*(1-Math.cos(x_rot))*(1-Math.cos(y_rot)));
    double d_xy = point_dist * (1 - Math.cos(x_rot)) * (1 - Math.cos(y_rot));
    hEllps += d_xy * Math.sin(ha);
    lla = globe.getEllipsoid().forwGeodesic(lat, lon, d_xy * Math.cos(ha), az, lla);
    lat = lla.lat;
    lon = lla.lon;
    az = Ellipsoid.adjlonPos(lla.az + Math.PI + x_rot);

    ha -= y_rot;
    if (ha > Math.PI / 2) ha = Math.PI / 2;
    if (ha < -Math.PI / 2) ha = -Math.PI / 2;
    ele_changed = lat_changed = lon_changed = az_changed = ha_changed = true;
    h = Double.MAX_VALUE;
  }
  public void translate(double d, double t_az, double t_ha, boolean correct_az) {
    if (globe == null || d == 0) return;
    double hDist = d * Math.cos(t_ha);
    double vDist = d * Math.sin(t_ha);

    lla = globe.getEllipsoid().forwGeodesic(lat, lon, hDist, t_az, lla);
    lat = lla.lat;
    lon = lla.lon;
    hEllps += vDist;
    if (correct_az) {
      az = Ellipsoid.adjlonPos(az + lla.az + Math.PI - t_az);
      az_changed = true;
    }
    ele_changed = lat_changed = lon_changed = true;
    h = Double.MAX_VALUE;
  }
 public Matrix4f computeViewMatrix(
     double lat, double lon, double hEllps, double az, double ha, Matrix4f mat) {
   if (mat == null) mat = new Matrix4f();
   if (globe != null)
     globe.getEllipsoid().computeSurfaceTransform(lat, lon, hEllps, az, ha, mat, origin);
   else mat.setIdentity();
   /*
   if (globe != null) {
     globe.getEllipsoid().toCartesian(lat, lon, hEllps, eye);
     eyeVector.set((float)(eye.x - origin.x),
                   (float)(eye.y - origin.y),
                   (float)(eye.z - origin.z));
   }
   else
     eyeVector.set(0,0,0);
   if (mat == null) mat = new Matrix4f();
   mat.set(eyeVector);
   workTrans.rotZ((float)(Math.PI/2.+lon)); mat.mul(workTrans);
   workTrans.rotX((float)(Math.PI/2.-lat)); mat.mul(workTrans);
   workTrans.rotZ((float)(-az));            mat.mul(workTrans);
   workTrans.rotX((float)(Math.PI/2.+ha));  mat.mul(workTrans);
    */
   return mat;
 }