Beispiel #1
0
 public GpsDevice() {
   m_latitude = new Measurement(java.lang.Math.toRadians(0), Unit.rad);
   m_longitude = new Measurement(java.lang.Math.toRadians(0), Unit.rad);
   m_altitude = new Measurement(0, Unit.m);
   m_speed = new Measurement(0, Unit.m_s);
   m_track = new Measurement(java.lang.Math.toRadians(0), Unit.rad);
 }
Beispiel #2
0
  @Override
  public void update(GameContainer gc, StateBasedGame sb, int delta) {

    float rotation = owner.getRotation();
    float scale = owner.getScale();
    Vector2f position = owner.getPosition();

    Input input = gc.getInput();

    if (input.isKeyDown(Input.KEY_LEFT)) {
      rotation += -0.2f * delta;
    }

    if (input.isKeyDown(Input.KEY_RIGHT)) {
      rotation += 0.2f * delta;
    }

    if (input.isKeyDown(Input.KEY_UP)) {
      float hip = 0.45f * delta;

      position.x += hip * java.lang.Math.sin(java.lang.Math.toRadians(rotation));
      position.y -= hip * java.lang.Math.cos(java.lang.Math.toRadians(rotation));
    }

    owner.setPosition(position);
    owner.setRotation(rotation);
    owner.setScale(scale);
  }
  /// @pre temps > 0
  /// @post Retorna una taula(t). t[0] i t[1] són les coordenades de n després de que hagui passat
  // temps iteracions
  double[] preveurePosicio(Nau n, double temps) {
    double dx = temps * n.velocitat_ * Math.cos(Math.toRadians(n.angleVelocitat_));
    double dy = temps * n.velocitat_ * -Math.sin(Math.toRadians(n.angleVelocitat_));

    double[] t = n.obtenirCentreTriangle();
    double centrex = t[0];
    double centrey = t[1];

    double[] previsio = {centrex + dx, centrey + dy};
    return previsio;
  }
  public void calculateClvsAlpha() {

    int nValue = 50;
    double alphaMin = Math.toRadians(-5);
    double alphaMax = Math.toRadians(25);
    alphaArray.linspace(alphaMin, alphaMax, nValue);
    double alpha;
    double q = _clStar - _clAlpha.getEstimatedValue() * _alphaStar.getEstimatedValue();
    clAirfoil = new double[nValue];
    for (int i = 0; i < nValue; i++) {

      alpha = alphaArray.get(i);
      if (alpha < _alphaStar.getEstimatedValue()) {
        clAirfoil[i] = _clAlpha.getEstimatedValue() * alpha + q;
      } else {
        double[][] matrixData = {
          {
            Math.pow(_alphaStall.getEstimatedValue(), 3),
            Math.pow(_alphaStall.getEstimatedValue(), 2),
            _alphaStall.getEstimatedValue(),
            1.0
          },
          {
            3 * Math.pow(_alphaStall.getEstimatedValue(), 2),
            2 * _alphaStall.getEstimatedValue(),
            1.0,
            0.0
          },
          {
            3 * Math.pow(_alphaStar.getEstimatedValue(), 2),
            2 * _alphaStar.getEstimatedValue(),
            1.0,
            0.0
          },
          {
            Math.pow(_alphaStar.getEstimatedValue(), 3),
            Math.pow(_alphaStar.getEstimatedValue(), 2),
            _alphaStar.getEstimatedValue(),
            1.0
          }
        };
        RealMatrix m = MatrixUtils.createRealMatrix(matrixData);
        double[] vector = {_clMax, 0, _clAlpha.getEstimatedValue(), _clStar};
        double[] solSystem = MyMathUtils.solveLinearSystem(m, vector);
        double a = solSystem[0];
        double b = solSystem[1];
        double c = solSystem[2];
        double d = solSystem[3];

        clAirfoil[i] = a * Math.pow(alpha, 3) + b * Math.pow(alpha, 2) + c * alpha + d;
      }
    }
  }
  /**
   * When scanning a robot we need to add it to the collection of scanned objects so it can be used
   * later for updates to the bots movement.
   */
  public void onScannedRobot(ScannedRobotEvent e) {
    double targetBearing = getHeading() + e.getBearing();
    double tmpX = getX() + e.getDistance() * Math.sin(Math.toRadians(targetBearing));
    double tmpY = getY() + e.getDistance() * Math.cos(Math.toRadians(targetBearing));
    String name = e.getName();

    if (name.equals(GOAL_NAME)) {
      foundGoal = true;
    }

    obstacles.put(name, new Enemy(tmpX, tmpY, e.getBearing()));

    setTurnRadarRight(getRadarTurnRemaining());
  }
Beispiel #6
0
  /*
   * requires a magnitude between -1 and 1 inclusive:
   * assumes that the angle is in degrees
   * calculates and sets the motor speeds for a given polar vector
   * allows for rotation while driving [-1,1]
   */
  private void driveMecanum() {

    /*
     * Does the computation of each motor speed value ever exceed the
     * range of -1.0, 1.0?  Just curious.
     *
     * - Mr. Ward
     */

    // RRLogger.logDebug(this.getClass(),"driveMecanum()", "driveMecanum()" );

    frontLeftMotor.set(-(l_magnitude + rotation) * Math.cos(Math.toRadians((l_angle + 45))));
    frontRightMotor.set((l_magnitude - rotation) * Math.sin(Math.toRadians(l_angle + 45)));
    backLeftMotor.set(-(l_magnitude + rotation) * Math.sin(Math.toRadians(l_angle + 45)));
    backRightMotor.set((l_magnitude - rotation) * Math.cos(Math.toRadians(l_angle + 45)));
  }
 protected void makeSheet() {
   if (false) { // TODO deal with sheets
     // sprite sheet is East 0, clockwise
     // direction sheet is North 0, clockwise
     /*int sheetIndex = (dir.ordinal() - Direction.EAST.ordinal() + 8) % 8;
        int soldierHeight = image.getHeight();
        if (!isAttacking()) {
     sheetIndex += 8;
        }
        image = image.getSubimage(sheetIndex * soldierHeight, 0,
     		      soldierHeight, soldierHeight);
        */
   } else {
     sprites = new BufferedImage[8];
     sprites[0] = image;
     for (int i = 1; i < 8; i++) {
       sprites[i] =
           new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
       double rotationRequired = Math.toRadians(i * 45);
       double locationX = image.getWidth() / 2;
       double locationY = image.getHeight() / 2;
       AffineTransform tx =
           AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
       AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
       // Drawing the rotated image at the required drawing locations
       sprites[i].createGraphics().drawImage(op.filter(image, null), 0, 0, null);
     }
   }
 }
Beispiel #8
0
 /* Converts an angle measured in degrees to an approximately equivalent angle measured in radians.
  */
 public static SchemaTypeNumber radians(SchemaTypeNumber value) {
   switch (value.numericType()) {
     case SchemaTypeNumber.NUMERIC_VALUE_INT:
       return new SchemaInt((int) java.lang.Math.toRadians(value.doubleValue()));
     case SchemaTypeNumber.NUMERIC_VALUE_LONG:
       return new SchemaLong((long) java.lang.Math.toRadians(value.doubleValue()));
     case SchemaTypeNumber.NUMERIC_VALUE_BIGINTEGER:
       return new SchemaInteger(
           (long)
               java.lang.Math.toRadians(value.doubleValue())); // note: possible loss of precision
     case SchemaTypeNumber.NUMERIC_VALUE_FLOAT:
       return new SchemaFloat((float) java.lang.Math.toRadians(value.doubleValue()));
     case SchemaTypeNumber.NUMERIC_VALUE_DOUBLE:
       return new SchemaDouble(java.lang.Math.toRadians(value.doubleValue()));
   }
   return new SchemaDecimal(java.lang.Math.toRadians(value.doubleValue()));
 }
Beispiel #9
0
    private void parseNmeaSentence(String scannedInput) {

      double lon, lat, speed, alt, track;

      // got a message... do a cksum
      if (!NmeaCksum(scannedInput)) {
        s_logger.error("NMEA checksum not valid");
        return;
      }
      // s_logger.info(scannedInput);
      m_lastSentence = scannedInput;
      NMEAParser gpsParser = new NMEAParser();

      gpsParser.parseSentence(scannedInput);
      m_validPosition = gpsParser.is_validPosition();
      // s_logger.debug("Parse : "+scannedInput+" position valid = "+m_validPosition);

      if (!m_validPosition) return;

      if (!scannedInput.startsWith("$G")) {
        // Invalid NMEA String. Return.
        s_logger.warn("Invalid NMEA sentence: " + scannedInput);
        return;
      }
      // Remove the first 3 characters from the input string in order to normalize the commands
      scannedInput = scannedInput.substring(3);

      if (scannedInput.startsWith("TXT")) {
        s_logger.debug("U-Blox init message: " + scannedInput);
      } else if (scannedInput.startsWith("GGA")) {
        try {
          lon = gpsParser.get_longNmea();
          lat = gpsParser.get_latNmea();
          alt = gpsParser.get_altNmea();
          m_fixQuality = gpsParser.get_fixQuality();
          m_latitude = new Measurement(java.lang.Math.toRadians(lat), Unit.rad);
          m_longitude = new Measurement(java.lang.Math.toRadians(lon), Unit.rad);
          m_altitude = new Measurement(alt, Unit.m);
          m_latitudeNmea = lat;
          m_longitudeNmea = lon;
          m_altitudeNmea = alt;
          m_DOP = gpsParser.get_DOPNmea();
          m_nrSatellites = gpsParser.get_nrSatellites();
          m_timeNmea = gpsParser.get_timeNmea();
        } catch (Exception e) {
          m_latitude = null;
          m_longitude = null;
          m_altitude = null;
          m_latitudeNmea = 0;
          m_longitudeNmea = 0;
          m_altitudeNmea = 0;
        }
      } else if (scannedInput.startsWith("GLL")) {
        try {
          lon = gpsParser.get_longNmea();
          lat = gpsParser.get_latNmea();
          m_latitude = new Measurement(java.lang.Math.toRadians(lat), Unit.rad);
          m_longitude = new Measurement(java.lang.Math.toRadians(lon), Unit.rad);
          m_latitudeNmea = lat;
          m_longitudeNmea = lon;
        } catch (Exception e) {
          m_latitude = null;
          m_longitude = null;
          m_latitudeNmea = 0;
          m_longitudeNmea = 0;
        }
      } else if (scannedInput.startsWith("GSA")) {
        try {
          m_PDOP = gpsParser.get_PDOPNmea();
          m_HDOP = gpsParser.get_HDOPNmea();
          m_VDOP = gpsParser.get_VDOPNmea();
          m_3Dfix = gpsParser.get_3DfixNmea();
          // System.out.println("m_PDOP = "+m_PDOP+"  m_HDOP = "+m_HDOP+"  m_VDOP = "+m_VDOP+"
          // m_3Dfix = "+m_3Dfix);
        } catch (Exception e) {
          m_PDOP = 0;
          m_HDOP = 0;
          m_VDOP = 0;
          m_3Dfix = 0;
        }
      } else if (scannedInput.startsWith("GSV")) {
      } else if (scannedInput.startsWith("RMC")) {
        try {
          lon = gpsParser.get_longNmea();
          lat = gpsParser.get_latNmea();
          speed = gpsParser.get_speedNmea();
          track = gpsParser.get_trackNmea();
          m_latitude = new Measurement(java.lang.Math.toRadians(lat), Unit.rad);
          m_longitude = new Measurement(java.lang.Math.toRadians(lon), Unit.rad);
          m_speed = new Measurement(speed, Unit.m_s);
          m_track = new Measurement(java.lang.Math.toRadians(track), Unit.rad);
          m_latitudeNmea = lat;
          m_longitudeNmea = lon;
          m_speedNmea = speed;
          m_trackNmea = track;
          m_dateNmea = gpsParser.get_dateNmea();
        } catch (Exception e) {
          m_latitude = null;
          m_longitude = null;
          m_speed = null;
          m_latitudeNmea = 0;
          m_longitudeNmea = 0;
          m_speedNmea = 0;
          m_trackNmea = 0;
        }
      } else if (scannedInput.startsWith("VTG")) {
        try {
          speed = gpsParser.get_speedNmea();
          m_speed = new Measurement(speed, Unit.m_s);
          m_speedNmea = speed;
        } catch (Exception e) {
          m_speed = null;
          m_speedNmea = 0;
        }
      } else if (scannedInput.indexOf("FOM") != -1) {
        // FOM = scannedInput;
      } else if (scannedInput.indexOf("PPS") != -1) {
        // PPS = scannedInput;
      } else {
        s_logger.warn("Unrecognized NMEA sentence: " + scannedInput);
      }
    }
  /** onScannedRobot: What to do when you see another robot */
  public void onScannedRobot(ScannedRobotEvent e) {
    System.out.println("START at : " + getTime() + " onScannedRobot----------------------------");
    String nnn = e.getName();
    System.out.println("scan " + nnn);
    double eneX =
        getX() + Math.sin(e.getBearingRadians() + Math.toRadians(getHeading())) * e.getDistance();
    double eneY =
        getY() + Math.cos(e.getBearingRadians() + Math.toRadians(getHeading())) * e.getDistance();
    Enemy_info enem = null;
    if (!isTeammate(nnn)) {
      // 味方への情報送信
      try {
        broadcastMessage(
            nnn
                + ", "
                + e.getBearing()
                + ", "
                + e.getBearingRadians()
                + ", "
                + e.getDistance()
                + ", "
                + e.getEnergy()
                + ", "
                + e.getHeading()
                + ", "
                + e.getHeadingRadians()
                + ", "
                + e.getVelocity()
                + ", "
                + eneX
                + ", "
                + eneY);
      } catch (IOException ignored) {
      }
      // スキャンした車両がLocal敵リストにいるかどうかのフラグ
      boolean flag = false;
      System.out.println("send scanned info");
      // スキャンした敵がLocal敵リストの中に存在するか
      for (Enemy_info temp : enes) {
        if (nnn.equals(temp.get_en_name())) {
          flag = true;
          enem = temp;
          // Local敵リストのアップデート
          temp.updateInformation(
              e.getBearing(),
              e.getBearingRadians(),
              e.getDistance(),
              e.getEnergy(),
              e.getHeading(),
              e.getHeadingRadians(),
              e.getVelocity(),
              eneX,
              eneY);
          System.out.println("	update scanned Info");
        }
      }
      // スキャンした敵がLocal敵リストの中に存在しない場合
      if (!flag) {
        // Local敵リストに新規追加
        enem =
            new Enemy_info(
                nnn,
                e.getBearing(),
                e.getBearingRadians(),
                e.getDistance(),
                e.getEnergy(),
                e.getHeading(),
                e.getHeadingRadians(),
                e.getVelocity(),
                eneX,
                eneY);
        enes.add(enem);
        System.out.println("	add scanned info");
      }
      if (enemy_detected == false) {
        // 共通の敵が設定されていない場合
        enemy_detected = true;
        target_enemy = enem;
        try {
          broadcastMessage("Kill , " + target_enemy.get_en_name() + ", !!");
        } catch (IOException ignored) {
        }
      }

      if (enemy_detected == true) {
        try {
          double enemyX = target_enemy.get_en_expX();
          double enemyY = target_enemy.get_en_expY();
          setTurnRadarLeftRadians(getRadarTurnRemainingRadians());

          System.out.println("abs : eX " + enemyX + " : " + "eY " + enemyY);

          // 共通の敵が設定されている場合
          double enemyBearing = Math.atan((enemyX - getX()) / (enemyY - getY()));
          // if(enemyBearing<0){
          // 	System.out.println("change");
          // 	enemyBearing = Math.PI*2 + enemyBearing;
          // }else if (enemyBearing < Math.PI){

          // }
          // System.out.println("atan " + Math.atan((eneY-getY())/(eneX-getX())));
          // System.out.println("atan1 " + Math.atan((eneX-getX())/(eneY-getY())));
          // System.out.println("trueeee " + (e.getBearingRadians() + this.getHeadingRadians()));
          System.out.println(
              "enerad"
                  + enemyBearing
                  + " ?= "
                  + "enemyBearing "
                  + (this.getHeadingRadians() + e.getBearingRadians()));
          System.out.println(enemyBearing + Math.PI);
          double enemyHeading = target_enemy.get_en_heading(); // 敵の向き
          System.out.println("enemy heading:" + enemyHeading);
          // double enemyBearing = this.getHeadingRadians() +
          // target_enemy.get_en_bearingRadians();// 自分と敵の角度

          // double enemyX = target_enemy.get_en_distance() * Math.sin(enemyBearing);
          // double enemyY = target_enemy.get_en_distance() * Math.cos(enemyBearing);

          enemyX = enemyX - getX();
          enemyY = enemyY - getY();
          System.out.println("Relative : eX " + enemyX + " : " + "eY " + enemyY);

          double battlefieldWidh = getBattleFieldWidth(); // フィールド幅
          double battlefieldHeight = getBattleFieldHeight(); // フィールド高さ

          boolean isHeadingToCenter = (int) enemyHeading % 90 == 0; // 中心を向いている
          boolean isOnWall =
              nearlyEquals(enemyX, 18)
                  || nearlyEquals(enemyX + 18, battlefieldWidh)
                  || nearlyEquals(enemyY, 18)
                  || nearlyEquals(enemyY + 18, battlefieldHeight); // 壁に張り付いている

          // 中心を向いている&&壁際にいる(=Walls)なら射撃
          if (isHeadingToCenter && isOnWall) {
            System.out.println("Walls!!");
          }

          double dis = 0;
          double heading = lastEnemyHeading;
          do {
            dis += Rules.getBulletSpeed(power);
            heading += target_enemy.get_en_headingRadians() - lastEnemyHeading;
            enemyX += target_enemy.get_en_velocity() * Math.sin(heading);
            enemyY += target_enemy.get_en_velocity() * Math.cos(heading);
          } while (dis < Point2D.distance(0, 0, enemyX, enemyY)); //

          // 相対角度に変換した上で砲塔の向きを変える
          setTurnGunRightRadians(
              Utils.normalRelativeAngle(Math.atan2(enemyX, enemyY) - getGunHeadingRadians()));
          setFire(power);
          // lastEnemyHeading = e.getHeadingRadians();
          lastEnemyHeading = target_enemy.get_en_headingRadians();
          System.out.println("lastEnemyHeading " + e.getHeadingRadians());
          System.out.println(lastEnemyHeading);

          // 敵の居る方向へターンする
          // setTurnRightRadians(e.getBearingRadians());
          setTurnRightRadians(enemyBearing - this.getHeadingRadians());
          System.out.println("setTurnRightRadians " + e.getBearingRadians());
          System.out.println(enemyBearing - this.getHeadingRadians());

          // 前進する
          setAhead(moveAmount);
        } catch (NullPointerException ee) {
          System.out.println("NullPointerException");
          System.out.println(target_enemy);
        }
      }
    }

    System.out.println("enemy_detected = " + enemy_detected);
    System.out.println("target is " + target_enemy.get_en_name());
    System.out.println(target_enemy.get_en_expX() + " " + target_enemy.get_en_expY());
    System.out.println("END at : " + getTime() + " onScannedRobot----------------------------");
  }
Beispiel #11
0
 public static void main(String[] args) {
   double deg = 30;
   double rad = Math.toRadians(deg);
   double ans = Math.atan(rad);
   System.out.println(ans);
 }
Beispiel #12
0
 /*
  * Drives the left and right wheels separately, with its repsective xbox stick
  * Allows for more precise rotation
  */
 private void driveTank() {
   frontLeftMotor.set(-(l_magnitude + rotation) * Math.cos(Math.toRadians((l_angle + 45))));
   frontRightMotor.set((r_magnitude - rotation) * Math.sin(Math.toRadians(r_angle + 45)));
   backLeftMotor.set(-(l_magnitude + rotation) * Math.sin(Math.toRadians(l_angle + 45)));
   backRightMotor.set((r_magnitude - rotation) * Math.cos(Math.toRadians(r_angle + 45)));
 }
  private void initializeAerodynamics(Airfoil airf, AirfoilEnum airfoilName) {
    switch (airfoilName) {
      case NACA23_018:
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;
        airf.setName(AirfoilEnum.NACA23_018);
        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-1.2), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.3, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(9.5), SI.RADIAN); // end-of-linearity
        _clStar = 1.3;
        _alphaStall = Amount.valueOf(Math.toRadians(16.0), SI.RADIAN);
        _clMax = 1.65; // 1.8;

        _cdMin = 0.00675;
        _clAtCdMin = 0.3;
        _kFactorDragPolar = 0.004;

        _aerodynamicCenterX = 0.243;
        _cmAC = -0.02;
        _cmACStall = -0.09;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case NACA23_015:
        airf.setName(AirfoilEnum.NACA23_015);
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-1.1), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.3, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(10), SI.RADIAN); // end-of-linearity
        _clStar = 1.2;
        _alphaStall = Amount.valueOf(Math.toRadians(18.0), SI.RADIAN);
        _clMax = 1.7; // 1.6;

        _cdMin = 0.00625;
        _clAtCdMin = 0.1;
        _kFactorDragPolar = 0.004;
        _aerodynamicCenterX = 0.243;
        _cmAC = -0.02;
        _cmACStall = -0.07;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case NACA23_012:
        airf.setName(AirfoilEnum.NACA23_012);
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-1.32), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.3, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(14), SI.RADIAN); // end-of-linearity
        _clStar = 1.6;
        _alphaStall = Amount.valueOf(Math.toRadians(18), SI.RADIAN);
        _clMax = 1.8; // 1.5;

        _cdMin = 0.00575;
        _clAtCdMin = 0.23;
        _kFactorDragPolar = 0.004;

        _aerodynamicCenterX = 0.247;
        _cmAC = -0.03;
        _cmACStall = -0.09;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case NACA65_209:
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-1.3), SI.RADIAN);
        _clAlpha = Amount.valueOf(5.96, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(11), SI.RADIAN); // end-of-linearity
        _clStar = 1.1;
        _alphaStall = Amount.valueOf(Math.toRadians(17.0), SI.RADIAN);
        _clMax = 1.6;

        _cdMin = 0.025;
        _clAtCdMin = 0.2;
        _kFactorDragPolar = 0.0035;

        _aerodynamicCenterX = 0.25;
        _cmAC = -0.07;
        _cmACStall = -0.09;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case NACA65_206:
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-1.4), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.13, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(10.0), SI.RADIAN); // end-of-linearity
        _clStar = _clAlpha.getEstimatedValue() * _alphaStar.getEstimatedValue();
        _alphaStall = Amount.valueOf(Math.toRadians(15.0), SI.RADIAN);
        _clMax = 1.3;

        _cdMin = 0.025;
        _clAtCdMin = 0.2;
        _kFactorDragPolar = 0.0035;

        _aerodynamicCenterX = 0.25;
        _cmAC = -0.07;
        _cmACStall = -0.09;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case NACA0012:
        airf.setName(AirfoilEnum.NACA0012);
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(0), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.92, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(11), SI.RADIAN); // end-of-linearity
        _clStar = 1.23;
        _alphaStall = Amount.valueOf(Math.toRadians(20.1), SI.RADIAN);
        _clMax = 1.86; // 1.5;

        _cdMin = 0.0055;
        _clAtCdMin = 0.0;
        _kFactorDragPolar = 0.0035;

        _aerodynamicCenterX = 0.25;
        _cmAC = 0.0;
        _cmACStall = -0.09;
        _cmAlphaAC = 0.;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;

      case DFVLR_R4:
        airf.setName(AirfoilEnum.DFVLR_R4);
        _id = airf.getId() + "1" + idCounter + "99";
        idCounter++;

        _theAirfoil = airf;
        geometry = airf.getGeometry();

        _alphaZeroLift = Amount.valueOf(Math.toRadians(-3.75), SI.RADIAN);
        _clAlpha = Amount.valueOf(6.3, SI.RADIAN.inverse());
        _alphaStar = Amount.valueOf(Math.toRadians(11), SI.RADIAN); // end-of-linearity
        _clStar = 1.53;
        _alphaStall = Amount.valueOf(Math.toRadians(16.75), SI.RADIAN);
        _clMax = 1.7671; // 1.5;

        _cdMin = 0.0056;
        _clAtCdMin = 0.0;
        _kFactorDragPolar = 0.075;

        _aerodynamicCenterX = 0.25;
        _cmAC = -0.1168;
        _cmACStall = -0.0515;
        _cmAlphaAC = 0.0015;
        calculateMachCr = new CalculateMachCr();
        calculateCdWaveDrag = new CalculateCdWaveDrag();
        break;
      default:
        break;
    }
  }
Beispiel #14
0
 /**
  * Create a unit vector based from the direction of the entity's head.
  *
  * <p>This equivalent to calling {@link #fromYawPitch(double, double)} using entity's rotations as
  * inputs.
  *
  * @param entity The entity to use
  */
 public static Vector fromEntityLook(Entity entity) {
   return fromYawPitch(Math.toRadians(entity.rotationYaw), Math.toRadians(entity.rotationPitch));
 }
Beispiel #15
0
 /**
  * <strong>Assuming</strong> this vector represents spherical coordinates in degrees, returns a
  * new spherical coordinate vector which is in radians.
  */
 public Vector toRadians() {
   return new Vector(Math.toRadians(x()), Math.toRadians(y()), Math.toRadians(z()));
 }
Beispiel #16
0
/** @author Mike Evers + Mal */
public class Human extends Character implements Serializable {

  private double flashlightRange = 200, flashlightAngle = Math.toRadians(30);
  private boolean hasKey;
  private double[][] flashlightPoints;

  private double flX3 = 0,
      flY3 = 0,
      flX2 = 0,
      flY2 = 0,
      flX1,
      flY1,
      flY23,
      flX32,
      flY31,
      flX13,
      flDet,
      flMinD,
      flMaxD;

  /**
   * this function sets the variable hasKey
   *
   * @param hasKey true if the human has the key.
   */
  public void setHasKey(boolean hasKey) {
    this.hasKey = hasKey;
  }

  /**
   * The Constructor for human. This initializes the flashlightRange, flashlightAngle and the
   * flashlightPoints by calling setFlashlight Also initialize the base class Character!
   */
  public Human() {
    super(null);
    this.hasKey = false;
  }

  /** @return true if human has picked up the key */
  public boolean hasKey() {
    return hasKey;
  }

  // <editor-fold defaultstate="collapsed" desc="Flashlight">
  /** @return the flashlight range */
  public double getFlashlightRange() {
    return this.flashlightRange;
  }

  /**
   * Sets the flashlight range
   *
   * @param flashlightRange
   */
  public void setFlashlightRange(int flashlightRange) {
    this.flashlightRange = flashlightRange;
  }

  /** @return the flashlight angle */
  public double getFlashlightAngle() {
    return this.flashlightAngle;
  }

  /**
   * Sets the flashlight angle
   *
   * @param flashlightAngle
   */
  public void setFlashlightAngle(int flashlightAngle) {
    this.flashlightAngle = flashlightAngle;
  }

  /**
   * Initializes the flashlight for the human. With this, the human can see the things in the level,
   * but only the things in range of the flashlight. Flashlight is a triangle.
   */
  private void setFlashlight() {
    flX1 = this.getPosition().getX() + 50;
    flY1 = this.getPosition().getY() + 50;
    switch (this.getDirection()) {
      case UP:
        flX2 = flX1 - tan(this.flashlightAngle) * this.flashlightRange;
        flY2 = flY1 - this.flashlightRange;
        flX3 = flX1 + tan(this.flashlightAngle) * this.flashlightRange;
        flY3 = flY1 - this.flashlightRange;
        break;
      case DOWN:
        flX2 = flX1 + tan(this.flashlightAngle) * this.flashlightRange;
        flX3 = flX1 - tan(this.flashlightAngle) * this.flashlightRange;
        flY2 = flY1 + this.flashlightRange;
        flY3 = flY2;
        break;
      case RIGHT:
        flX2 = flX1 + this.flashlightRange;
        flX3 = flX2;
        flY2 = flY1 + tan(this.flashlightAngle) * this.flashlightRange;
        flY3 = flY1 - tan(this.flashlightAngle) * this.flashlightRange;
        break;
      case LEFT:
        flX2 = flX1 - this.flashlightRange;
        flX3 = flX2;
        flY2 = flY1 + tan(this.flashlightAngle) * this.flashlightRange;
        flY3 = flY1 - tan(this.flashlightAngle) * this.flashlightRange;
        break;
    }
  }

  /**
   * Returns the coordinates of the flashlight polygon So the fx part can draw this for the human.
   *
   * @return polygon of the flashlight.
   */
  public int[] getFlashlightPolygon() {
    int[] i = new int[6];
    i[0] = (int) this.getPosition().getX() + 50;
    i[1] = (int) this.getPosition().getY() + 50;
    i[2] = (int) flX2;
    i[3] = (int) flY2;
    i[4] = (int) flX3;
    i[5] = (int) flY3;
    return i;
  }

  // </editor-fold>
  /** if haskey == false, hasKey becomes true */
  public void pickUpKey() {
    if (!hasKey) {
      hasKey = true;
    }
  }

  /**
   * if haskey == true, enterDoor will cause endround, so the game can continue to the next round or
   * go to the victory screen. Otherwise, this method won't cause anything.
   *
   * @param game
   * @throws java.lang.InterruptedException
   * @throws java.io.IOException
   */
  public void enterDoor(Game game) throws InterruptedException, IOException {
    // First check if this entering was on the last floor (last level).
    if (game.getFloorAmount() == game.getCurrentFloor()) {
      boolean humanFound = false;

      while (!humanFound) {
        for (IPlayer player : game.getPlayers()) {
          try {
            if (player.getCharacter() instanceof Human) {
              game.endGame();
              humanFound = true;
            }
          } catch (RemoteException ex) {
            Logger.getLogger(Human.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
      }
    } else {
      game.setRoundEnded(true);
    }
  }

  /**
   * check if hitbox collides with the points
   *
   * @param point1
   * @param width1
   * @param height1
   * @param point2
   * @param width2
   * @param height2
   * @return
   */
  public boolean checkHitboxCollision(
      Point2D point1, int width1, int height1, Point2D point2, int width2, int height2) {
    // convert point1 in leftmost and rightmost X value and top and bottom Y value;
    int p1Xmin = (int) point1.getX();
    int p1Xmax = (int) p1Xmin + width1 - 1;
    int p1Ymin = (int) point1.getY();
    int p1Ymax = (int) p1Ymin + height1 - 1;

    // convert point2 in leftmost and rightmost X value and top and bottom Y value;
    int p2Xmin = (int) point2.getX();
    int p2Xmax = (int) p2Xmin + width2 - 1;
    int p2Ymin = (int) point2.getY();
    int p2Ymax = (int) p2Ymin + height2 - 1;

    return (betweenInclusive(p1Xmax, p2Xmin, p2Xmax)
            && (betweenInclusive(p1Ymin, p2Ymin, p2Ymax)
                || betweenInclusive(p1Ymax, p2Ymin, p2Ymax)))
        || (betweenInclusive(p1Xmin, p2Xmin, p2Xmax)
            && (betweenInclusive(p1Ymin, p2Ymin, p2Ymax)
                || betweenInclusive(p1Ymax, p2Ymin, p2Ymax)));
  }

  /**
   * check if human collides with a ghost
   *
   * @param game
   * @return the ghost where the human collides with
   */
  public Ghost checkGhostCollision(Game game) {
    // ghost collision
    for (Ghost ghost : game.getGhosts()) {
      if (!ghost.getRip() && !ghost.getDead()) {
        if (checkHitboxCollision(this.getPosition(), 90, 90, ghost.getPosition(), 90, 90)) {
          return ghost;
        }
      }
    }
    return null;
  }

  /**
   * check if the given position collides with the flashlight.
   *
   * @param point
   * @return
   */
  public boolean flashlightCollision(Point2D point) {

    flY23 = flY2 - flY3;
    flX32 = flX3 - flX2;
    flY31 = flY3 - flY1;
    flX13 = flX1 - flX3;
    flDet = flY23 * flX13 - flX32 * flY31;
    flMinD = Math.min(flDet, 0);
    flMaxD = Math.max(flDet, 0);

    double x = point.getX();
    double y = point.getY();
    double dx = x - flX3;
    double dy = y - flY3;
    double a = flY23 * dx + flX32 * dy;
    if (a < flMinD || a > flMaxD) {
      return false;
    }
    double b = flY31 * dx + flX13 * dy;
    if (b < flMinD || b > flMaxD) {
      return false;
    }
    double c = flDet - a - b;
    return !(c < flMinD || c > flMaxD);
  }

  /**
   * check if the human interacts with ghost, key, door or wall
   *
   * @param game
   * @throws java.lang.InterruptedException
   * @throws java.io.IOException
   */
  public void checkInteract(Game game) throws InterruptedException, IOException {
    DirectionType doorDisplacement = game.getLevel().getDoorDirection();
    Point2D door =
        new Point2D.Double(
            game.getLevel().getDoorLocation().getX(), game.getLevel().getDoorLocation().getY());
    switch (doorDisplacement) {
      case UP:
        door.setLocation(door.getX(), door.getY() - 100);
        break;
      case RIGHT:
        door.setLocation(door.getX() + 100, door.getY());
        break;
      case LEFT:
        door.setLocation(door.getX() - 100, door.getY());
        break;
      case DOWN:
        door.setLocation(door.getX(), door.getY() + 100);
        break;
    }
    Point2D key = game.getLevel().getKeyLocation();

    // door collision
    if ((checkHitboxCollision(
            new Point2D.Double(this.getPosition().getX() + 10, this.getPosition().getY() + 10),
            80,
            80,
            new Point2D.Double(door.getX() - 5, door.getY() - 5),
            110,
            110)
        && this.hasKey)) // key collision
    {
      this.enterDoor(game);
    }
    // key collision
    if (checkHitboxCollision(this.getPosition(), 80, 80, key, 80, 80)) {
      this.pickUpKey();
    }
    // flashlight and ghost collision
    if (this.checkGhostCollision(game) != null) {
      this.checkGhostCollision(game).possess(game);
    }
    setFlashlight();
    game.getGhosts()
        .stream()
        .forEach(
            (g) -> {
              if (g.isVulnerable() && !g.getRip() && !g.getDead()) {
                boolean hit = false;
                for (Point2D p : g.getHitboxPoints()) {
                  if (flashlightCollision(p)) {
                    hit = true;
                    break;
                  }
                }
                if (hit) {
                  g.setTimeOfDeath();
                  g.vanish(game);
                }
              }
            });
  }
}
Beispiel #17
0
 private static double apparentLongitude(double omicron, double omega, double t) {
   return omicron - 0.00569 - 0.00478 * Math.sin(Math.toRadians(omega));
 }
Beispiel #18
0
/**
 * Computes the distance, azimuth, and back azimuth between two lat-lon positions on the Earth's
 * surface. Reference ellipsoid is the WGS-84.
 *
 * <p>You may use a default Earth (equator radius = 6378137.0 meters, flattening = 1.0 /
 * 298.257223563) or you may define your own using a ucar.unidata.geoloc.Earth object.
 *
 * @author Unidata Development Team
 */
public class Bearing {

  /** Default Earth. Major radius and flattening; */
  private static final Earth defaultEarth = new Earth(6378137.0, 0., 298.257223563);

  /** Earth radius */
  private static double A;
  // private static double A = 6378137.0;  // in meters (for reference)

  /** The Earth flattening value */
  private static double F;
  // private static double F = 1.0 / 298.257223563;  (for reference)

  /** epsilon */
  private static final double EPS = 0.5E-13;

  /** constant R */
  // private static final double R = 1.0 - F;  (for reference)
  private static double R;

  /** conversion for degrees to radians */
  private static final double rad = Math.toRadians(1.0);

  /** conversion for radians to degrees */
  private static final double deg = Math.toDegrees(1.0);

  /**
   * Calculate the bearing between the 2 points. See calculateBearing below.
   *
   * @param e Earth object (defines radius & flattening)
   * @param pt1 Point 1
   * @param pt2 Point 2
   * @param result Object to use if non-null
   * @return The bearing
   */
  public static Bearing calculateBearing(
      Earth e, LatLonPoint pt1, LatLonPoint pt2, Bearing result) {

    return calculateBearing(
        e, pt1.getLatitude(), pt1.getLongitude(), pt2.getLatitude(), pt2.getLongitude(), result);
  }

  /**
   * Calculate the bearing between the 2 points. See calculateBearing below. Uses default Earth
   * object.
   *
   * @param pt1 Point 1
   * @param pt2 Point 2
   * @param result Object to use if non-null
   * @return The bearing
   */
  public static Bearing calculateBearing(LatLonPoint pt1, LatLonPoint pt2, Bearing result) {

    return calculateBearing(
        defaultEarth,
        pt1.getLatitude(),
        pt1.getLongitude(),
        pt2.getLatitude(),
        pt2.getLongitude(),
        result);
  }

  /** _more_ */
  private static int maxLoopCnt = 0;

  /**
   * Computes distance (in km), azimuth (degrees clockwise positive from North, 0 to 360), and back
   * azimuth (degrees clockwise positive from North, 0 to 360), from latitude-longituide point pt1
   * to latitude-longituide pt2. Uses default Earth object.
   *
   * @param lat1 Lat of point 1
   * @param lon1 Lon of point 1
   * @param lat2 Lat of point 2
   * @param lon2 Lon of point 2
   * @param result put result here, or null to allocate
   * @return a Bearing object with distance (in km), azimuth from pt1 to pt2 (degrees, 0 = north,
   *     clockwise positive)
   */
  public static Bearing calculateBearing(
      double lat1, double lon1, double lat2, double lon2, Bearing result) {

    return calculateBearing(defaultEarth, lat1, lon1, lat2, lon2, result);
  }

  /**
   * Computes distance (in km), azimuth (degrees clockwise positive from North, 0 to 360), and back
   * azimuth (degrees clockwise positive from North, 0 to 360), from latitude-longituide point pt1
   * to latitude-longituide pt2.
   *
   * <p>Algorithm from U.S. National Geodetic Survey, FORTRAN program "inverse," subroutine
   * "INVER1," by L. PFEIFER and JOHN G. GERGEN. See
   * http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html
   *
   * <p>Original documentation: <br>
   * SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY <br>
   * MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS <br>
   * EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL <br>
   * STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE Reference ellipsoid is the WGS-84
   * ellipsoid. <br>
   * See http://www.colorado.edu/geography/gcraft/notes/datum/elist.html
   *
   * <p>Requires close to 1.4 E-5 seconds wall clock time per call on a 550 MHz Pentium with Linux
   * 7.2.
   *
   * @param e Earth object (defines radius and flattening)
   * @param lat1 Lat of point 1
   * @param lon1 Lon of point 1
   * @param lat2 Lat of point 2
   * @param lon2 Lon of point 2
   * @param result put result here, or null to allocate
   * @return a Bearing object with distance (in km), azimuth from pt1 to pt2 (degrees, 0 = north,
   *     clockwise positive)
   */
  public static Bearing calculateBearing(
      Earth e, double lat1, double lon1, double lat2, double lon2, Bearing result) {

    if (result == null) {
      result = new Bearing();
    }

    if ((lat1 == lat2) && (lon1 == lon2)) {
      result.distance = 0;
      result.azimuth = 0;
      result.backazimuth = 0;
      return result;
    }

    A = e.getMajor();
    F = e.getFlattening();
    R = 1.0 - F;

    // Algorithm from National Geodetic Survey, FORTRAN program "inverse,"
    // subroutine "INVER1," by L. PFEIFER and JOHN G. GERGEN.
    // http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html
    // Conversion to JAVA from FORTRAN was made with as few changes as possible
    // to avoid errors made while recasting form, and to facilitate any future
    // comparisons between the original code and the altered version in Java.
    // Original documentation:
    // SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY
    // MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS
    // EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL
    // STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE
    // A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID
    // F IS THE FLATTENING (NOT RECIPROCAL) OF THE REFERNECE ELLIPSOID
    // LATITUDES GLAT1 AND GLAT2
    // AND LONGITUDES GLON1 AND GLON2 ARE IN RADIANS POSITIVE NORTH AND EAST
    // FORWARD AZIMUTHS AT BOTH POINTS RETURNED IN RADIANS FROM NORTH
    //
    // Reference ellipsoid is the WGS-84 ellipsoid.
    // See http://www.colorado.edu/geography/gcraft/notes/datum/elist.html
    // FAZ is forward azimuth in radians from pt1 to pt2;
    // BAZ is backward azimuth from point 2 to 1;
    // S is distance in meters.
    //
    // Conversion to JAVA from FORTRAN was made with as few changes as possible
    // to avoid errors made while recasting form, and to facilitate any future
    // comparisons between the original code and the altered version in Java.
    //
    // IMPLICIT REAL*8 (A-H,O-Z)
    //  COMMON/CONST/PI,RAD
    //  COMMON/ELIPSOID/A,F
    double GLAT1 = rad * lat1;
    double GLAT2 = rad * lat2;
    double TU1 = R * Math.sin(GLAT1) / Math.cos(GLAT1);
    double TU2 = R * Math.sin(GLAT2) / Math.cos(GLAT2);
    double CU1 = 1. / Math.sqrt(TU1 * TU1 + 1.);
    double SU1 = CU1 * TU1;
    double CU2 = 1. / Math.sqrt(TU2 * TU2 + 1.);
    double S = CU1 * CU2;
    double BAZ = S * TU2;
    double FAZ = BAZ * TU1;
    double GLON1 = rad * lon1;
    double GLON2 = rad * lon2;
    double X = GLON2 - GLON1;
    double D, SX, CX, SY, CY, Y, SA, C2A, CZ, E, C;
    int loopCnt = 0;
    do {
      loopCnt++;
      // Check for an infinite loop
      if (loopCnt > 1000) {
        throw new IllegalArgumentException(
            "Too many iterations calculating bearing:"
                + lat1
                + " "
                + lon1
                + " "
                + lat2
                + " "
                + lon2);
      }
      SX = Math.sin(X);
      CX = Math.cos(X);
      TU1 = CU2 * SX;
      TU2 = BAZ - SU1 * CU2 * CX;
      SY = Math.sqrt(TU1 * TU1 + TU2 * TU2);
      CY = S * CX + FAZ;
      Y = Math.atan2(SY, CY);
      SA = S * SX / SY;
      C2A = -SA * SA + 1.;
      CZ = FAZ + FAZ;
      if (C2A > 0.) {
        CZ = -CZ / C2A + CY;
      }
      E = CZ * CZ * 2. - 1.;
      C = ((-3. * C2A + 4.) * F + 4.) * C2A * F / 16.;
      D = X;
      X = ((E * CY * C + CZ) * SY * C + Y) * SA;
      X = (1. - C) * X * F + GLON2 - GLON1;
      // IF(DABS(D-X).GT.EPS) GO TO 100
    } while (Math.abs(D - X) > EPS);

    if (loopCnt > maxLoopCnt) {
      maxLoopCnt = loopCnt;
      //        System.err.println("loopCnt:" + loopCnt);
    }

    FAZ = Math.atan2(TU1, TU2);
    BAZ = Math.atan2(CU1 * SX, BAZ * CX - SU1 * CU2) + Math.PI;
    X = Math.sqrt((1. / R / R - 1.) * C2A + 1.) + 1.;
    X = (X - 2.) / X;
    C = 1. - X;
    C = (X * X / 4. + 1.) / C;
    D = (0.375 * X * X - 1.) * X;
    X = E * CY;
    S = 1. - E - E;
    S = ((((SY * SY * 4. - 3.) * S * CZ * D / 6. - X) * D / 4. + CZ) * SY * D + Y) * C * A * R;

    result.distance = S / 1000.0; // meters to km
    result.azimuth = FAZ * deg; // radians to degrees

    if (result.azimuth < 0.0) {
      result.azimuth += 360.0; // reset azs from -180 to 180 to 0 to 360
    }

    result.backazimuth = BAZ * deg; // radians to degrees; already in 0 to 360 range

    return result;
  }

  /*
   * This method is for same use as calculateBearing, but has much simpler calculations
   * by assuming a spherical earth. It is actually slower than
   * "calculateBearing" code, probably due to having more trig function calls.
   * It is less accurate, too.
   * Errors are on the order of 1/300 or less. This code
   * saved here only as a warning to future programmers thinking of this approach.
   *
   * Requires close to 2.0 E-5 seconds wall clock time per call
   * on a 550 MHz Pentium with Linux 7.2.
   *
   * public static Bearing calculateBearingAlternate
   *   (LatLonPoint pt1, LatLonPoint pt2, Bearing result) {
   *
   * // to convert degrees to radians, multiply by:
   * final double rad = Math.toRadians(1.0);
   * // to convert radians to degrees:
   * final double deg = Math.toDegrees(1.0);
   *
   * if (result == null)
   *   result = new Bearing();
   *
   * double R = 6371008.7;  // mean earth radius in meters; WGS 84 definition
   * double GLAT1 = rad*(pt1.getLatitude());
   * double GLAT2 = rad*(pt2.getLatitude());
   * double GLON1 = rad*(pt1.getLongitude());
   * double GLON2 = rad*(pt2.getLongitude());
   *
   * // great circle angular separation in radians
   * double alpha = Math.acos( Math.sin(GLAT1)*Math.sin(GLAT2)
   *                          +Math.cos(GLAT1)*Math.cos(GLAT2)*Math.cos(GLON1-GLON2) );
   * // great circle distance in meters
   * double gcd = R * alpha;
   *
   * result.distance = gcd / 1000.0;      // meters to km
   *
   * // forward azimuth from point 1 to 2 in radians
   * double s2 = rad*(90.0-pt2.getLatitude());
   * double FAZ = Math.asin(Math.sin(s2)*Math.sin(GLON2-GLON1) / Math.sin(alpha));
   *
   * result.azimuth = FAZ * deg;        // radians to degrees
   * if (result.azimuth < 0.0)
   * result.azimuth += 360.0;       // reset az from -180 to 180 to 0 to 360
   *
   * // back azimuth from point 2 to 1 in radians
   * double s1 = rad*(90.0-pt1.getLatitude());
   * double BAZ = Math.asin(Math.sin(s1)*Math.sin(GLON1-GLON2) / Math.sin(alpha));
   *
   * result.backazimuth = BAZ * deg;
   * if (result.backazimuth < 0.0)
   *     result.backazimuth += 360.0;   // reset backaz from -180 to 180 to 0 to 360
   *
   * return result;
   * }
   */

  /** the azimuth, degrees, 0 = north, clockwise positive */
  private double azimuth;

  /** the back azimuth, degrees, 0 = north, clockwise positive */
  private double backazimuth;

  /** separation in kilometers */
  private double distance;

  /**
   * Get the azimuth in degrees, 0 = north, clockwise positive
   *
   * @return azimuth in degrees
   */
  public double getAngle() {
    return azimuth;
  }

  /**
   * Get the back azimuth in degrees, 0 = north, clockwise positive
   *
   * @return back azimuth in degrees
   */
  public double getBackAzimuth() {
    return backazimuth;
  }

  /**
   * Get the distance in kilometers
   *
   * @return distance in km
   */
  public double getDistance() {
    return distance;
  }

  /**
   * Nice format.
   *
   * @return return a nice format of this Bearing
   */
  public String toString() {
    StringBuilder buf = new StringBuilder();
    buf.append("Azimuth: ");
    buf.append(azimuth);
    buf.append(" Back azimuth: ");
    buf.append(backazimuth);
    buf.append(" Distance: ");
    buf.append(distance);
    return buf.toString();
  }

  /**
   * Test the calculations - forward and back
   *
   * @param args non used
   */
  public static void main(String[] args) {
    // Bearing         workBearing = new Bearing();
    LatLonPointImpl pt1 = new LatLonPointImpl(40, -105);
    LatLonPointImpl pt2 = new LatLonPointImpl(37.4, -118.4);
    Bearing b = calculateBearing(pt1, pt2, null);
    System.out.println("Bearing from " + pt1 + " to " + pt2 + " = \n\t" + b);
    LatLonPointImpl pt3 = new LatLonPointImpl();
    pt3 = findPoint(pt1, b.getAngle(), b.getDistance(), pt3);
    System.out.println("using first point, angle and distance, found second point at " + pt3);
    pt3 = findPoint(pt2, b.getBackAzimuth(), b.getDistance(), pt3);
    System.out.println("using second point, backazimuth and distance, found first point at " + pt3);
    /*  uncomment for timing tests
    for(int j=0;j<10;j++) {
        long t1 = System.currentTimeMillis();
        for(int i=0;i<30000;i++) {
            workBearing = Bearing.calculateBearing(42.5,-93.0,
                                                   48.9,-117.09,workBearing);
        }
        long t2 = System.currentTimeMillis();
        System.err.println ("time:" + (t2-t1));
    }
    */
  }

  /**
   * Calculate a position given an azimuth and distance from another point.
   *
   * @param e Earth object (defines radius and flattening)
   * @param pt1 Point 1
   * @param az azimuth (degrees)
   * @param dist distance from the point (km)
   * @param result Object to use if non-null
   * @return The LatLonPoint
   * @see #findPoint(double,double,double,double,LatLonPointImpl)
   */
  public static LatLonPointImpl findPoint(
      Earth e, LatLonPoint pt1, double az, double dist, LatLonPointImpl result) {
    return findPoint(e, pt1.getLatitude(), pt1.getLongitude(), az, dist, result);
  }

  /**
   * Calculate a position given an azimuth and distance from another point. Uses default Earth.
   *
   * @param pt1 Point 1
   * @param az azimuth (degrees)
   * @param dist distance from the point (km)
   * @param result Object to use if non-null
   * @return The LatLonPoint
   * @see #findPoint(double,double,double,double,LatLonPointImpl)
   */
  public static LatLonPointImpl findPoint(
      LatLonPoint pt1, double az, double dist, LatLonPointImpl result) {
    return findPoint(defaultEarth, pt1.getLatitude(), pt1.getLongitude(), az, dist, result);
  }

  /**
   * Calculate a position given an azimuth and distance from another point. See details, below. Uses
   * default Earth.
   *
   * @param lat1 latitude of starting point
   * @param lon1 longitude of starting point
   * @param az forward azimuth (degrees)
   * @param dist distance from the point (km)
   * @param result Object to use if non-null
   * @return the position as a LatLonPointImpl
   */
  public static LatLonPointImpl findPoint(
      double lat1, double lon1, double az, double dist, LatLonPointImpl result) {
    return findPoint(defaultEarth, lat1, lon1, az, dist, result);
  }

  /**
   * Calculate a position given an azimuth and distance from another point.
   *
   * <p>
   *
   * <p>Algorithm from National Geodetic Survey, FORTRAN program "forward," subroutine "DIRCT1," by
   * stephen j. frakes. http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html
   *
   * <p>Original documentation:
   *
   * <pre>
   *    SOLUTION OF THE GEODETIC DIRECT PROBLEM AFTER T.VINCENTY
   *    MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS
   *    EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL
   *  </pre>
   *
   * @param e Earth object (defines radius and flattening)
   * @param lat1 latitude of starting point
   * @param lon1 longitude of starting point
   * @param az forward azimuth (degrees)
   * @param dist distance from the point (km)
   * @param result Object to use if non-null
   * @return the position as a LatLonPointImpl
   */
  public static LatLonPointImpl findPoint(
      Earth e, double lat1, double lon1, double az, double dist, LatLonPointImpl result) {
    if (result == null) {
      result = new LatLonPointImpl();
    }

    if ((dist == 0)) {
      result.setLatitude(lat1);
      result.setLongitude(lon1);
      return result;
    }

    A = e.getMajor();
    F = e.getFlattening();
    R = 1.0 - F;

    // Algorithm from National Geodetic Survey, FORTRAN program "forward,"
    // subroutine "DIRCT1," by stephen j. frakes.
    // http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html
    // Conversion to JAVA from FORTRAN was made with as few changes as
    // possible to avoid errors made while recasting form, and
    // to facilitate any future comparisons between the original
    // code and the altered version in Java.
    // Original documentation:
    //   SUBROUTINE DIRCT1(GLAT1,GLON1,GLAT2,GLON2,FAZ,BAZ,S)
    //
    //   SOLUTION OF THE GEODETIC DIRECT PROBLEM AFTER T.VINCENTY
    //   MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS
    //   EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL
    //
    //   A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID
    //   F IS THE FLATTENING OF THE REFERENCE ELLIPSOID
    //   LATITUDES AND LONGITUDES IN RADIANS POSITIVE NORTH AND EAST
    //   AZIMUTHS IN RADIANS CLOCKWISE FROM NORTH
    //   GEODESIC DISTANCE S ASSUMED IN UNITS OF SEMI-MAJOR AXIS A
    //
    //   PROGRAMMED FOR CDC-6600 BY LCDR L.PFEIFER NGS ROCKVILLE MD 20FEB75
    //   MODIFIED FOR SYSTEM 360 BY JOHN G GERGEN NGS ROCKVILLE MD 750608
    //

    if (az < 0.0) {
      az += 360.0; // reset azs from -180 to 180 to 0 to 360
    }
    double FAZ = az * rad;
    double GLAT1 = lat1 * rad;
    double GLON1 = lon1 * rad;
    double S = dist * 1000.; // convert to meters
    double TU = R * Math.sin(GLAT1) / Math.cos(GLAT1);
    double SF = Math.sin(FAZ);
    double CF = Math.cos(FAZ);
    double BAZ = 0.;
    if (CF != 0) {
      BAZ = Math.atan2(TU, CF) * 2;
    }
    double CU = 1. / Math.sqrt(TU * TU + 1.);
    double SU = TU * CU;
    double SA = CU * SF;
    double C2A = -SA * SA + 1.;
    double X = Math.sqrt((1. / R / R - 1.) * C2A + 1.) + 1.;
    X = (X - 2.) / X;
    double C = 1. - X;
    C = (X * X / 4. + 1) / C;
    double D = (0.375 * X * X - 1.) * X;
    TU = S / R / A / C;
    double Y = TU;
    double SY, CY, CZ, E, GLAT2, GLON2;
    do {
      SY = Math.sin(Y);
      CY = Math.cos(Y);
      CZ = Math.cos(BAZ + Y);
      E = CZ * CZ * 2. - 1.;
      C = Y;
      X = E * CY;
      Y = E + E - 1.;
      Y = (((SY * SY * 4. - 3.) * Y * CZ * D / 6. + X) * D / 4. - CZ) * SY * D + TU;
    } while (Math.abs(Y - C) > EPS);
    BAZ = CU * CY * CF - SU * SY;
    C = R * Math.sqrt(SA * SA + BAZ * BAZ);
    D = SU * CY + CU * SY * CF;
    GLAT2 = Math.atan2(D, C);
    C = CU * CY - SU * SY * CF;
    X = Math.atan2(SY * SF, C);
    C = ((-3. * C2A + 4.) * F + 4.) * C2A * F / 16.;
    D = ((E * CY * C + CZ) * SY * C + Y) * SA;
    GLON2 = GLON1 + X - (1. - C) * D * F;
    BAZ = (Math.atan2(SA, BAZ) + Math.PI) * deg;
    result.setLatitude(GLAT2 * deg);
    result.setLongitude(GLON2 * deg);
    return result;
  }
}