protected void doMoveAirspaceLaterally(
      WorldWindow wwd, Airspace airspace, Point mousePoint, Point previousMousePoint) {
    // Intersect a ray throuh each mouse point, with a geoid passing through the reference
    // elevation. Since
    // most airspace control points follow a fixed altitude, this will track close to the intended
    // mouse position.
    // If either ray fails to intersect the geoid, then ignore this event. Use the difference
    // between the two
    // intersected positions to move the control point's location.

    if (!(airspace instanceof Movable)) {
      return;
    }

    Movable movable = (Movable) airspace;
    View view = wwd.getView();
    Globe globe = wwd.getModel().getGlobe();

    Position refPos = movable.getReferencePosition();
    if (refPos == null) return;

    // Convert the reference position into a cartesian point. This assumes that the reference
    // elevation is defined
    // by the airspace's lower altitude.
    Vec4 refPoint = null;
    if (airspace.isTerrainConforming()[LOWER_ALTITUDE])
      refPoint = wwd.getSceneController().getTerrain().getSurfacePoint(refPos);
    if (refPoint == null) refPoint = globe.computePointFromPosition(refPos);

    // Convert back to a position.
    refPos = globe.computePositionFromPoint(refPoint);

    Line ray = view.computeRayFromScreenPoint(mousePoint.getX(), mousePoint.getY());
    Line previousRay =
        view.computeRayFromScreenPoint(previousMousePoint.getX(), previousMousePoint.getY());

    Vec4 vec = AirspaceEditorUtil.intersectGlobeAt(wwd, refPos.getElevation(), ray);
    Vec4 previousVec = AirspaceEditorUtil.intersectGlobeAt(wwd, refPos.getElevation(), previousRay);

    if (vec == null || previousVec == null) {
      return;
    }

    Position pos = globe.computePositionFromPoint(vec);
    Position previousPos = globe.computePositionFromPoint(previousVec);
    LatLon change = pos.subtract(previousPos);

    movable.move(new Position(change.getLatitude(), change.getLongitude(), 0.0));

    this.fireAirspaceMoved(new AirspaceEditEvent(wwd, airspace, this));
  }
  protected void doMoveAirspaceVertically(
      WorldWindow wwd, Airspace airspace, Point mousePoint, Point previousMousePoint) {
    // Find the closest points between the rays through each screen point, and the ray from the
    // control point
    // and in the direction of the globe's surface normal. Compute the elevation difference between
    // these two
    // points, and use that as the change in airspace altitude.
    //
    // If the state keepControlPointsAboveTerrain is set, we prevent the control point from passing
    // any lower than
    // the terrain elevation beneath it.

    if (!(airspace instanceof Movable)) {
      return;
    }

    Movable movable = (Movable) airspace;
    Position referencePos = movable.getReferencePosition();
    if (referencePos == null) return;

    Vec4 referencePoint = wwd.getModel().getGlobe().computePointFromPosition(referencePos);

    Vec4 surfaceNormal =
        wwd.getModel()
            .getGlobe()
            .computeSurfaceNormalAtLocation(
                referencePos.getLatitude(), referencePos.getLongitude());
    Line verticalRay = new Line(referencePoint, surfaceNormal);
    Line screenRay =
        wwd.getView()
            .computeRayFromScreenPoint(previousMousePoint.getX(), previousMousePoint.getY());
    Line previousScreenRay =
        wwd.getView().computeRayFromScreenPoint(mousePoint.getX(), mousePoint.getY());

    Vec4 pointOnLine = AirspaceEditorUtil.nearestPointOnLine(verticalRay, screenRay);
    Vec4 previousPointOnLine =
        AirspaceEditorUtil.nearestPointOnLine(verticalRay, previousScreenRay);

    Position pos = wwd.getModel().getGlobe().computePositionFromPoint(pointOnLine);
    Position previousPos = wwd.getModel().getGlobe().computePositionFromPoint(previousPointOnLine);
    double elevationChange = previousPos.getElevation() - pos.getElevation();

    double[] altitudes = this.getAirspace().getAltitudes();
    boolean[] terrainConformance = this.getAirspace().isTerrainConforming();

    if (this.isKeepControlPointsAboveTerrain()) {
      if (terrainConformance[LOWER_ALTITUDE]) {
        if (altitudes[LOWER_ALTITUDE] + elevationChange < 0.0)
          elevationChange = 0.0 - altitudes[LOWER_ALTITUDE];
      } else {
        double height =
            AirspaceEditorUtil.computeLowestHeightAboveSurface(
                wwd, this.getCurrentControlPoints(), LOWER_ALTITUDE);
        if (elevationChange <= -height) {
          elevationChange = -height;
        }
      }
    }

    altitudes[LOWER_ALTITUDE] += elevationChange;
    altitudes[UPPER_ALTITUDE] += elevationChange;
    this.getAirspace().setAltitudes(altitudes[LOWER_ALTITUDE], altitudes[UPPER_ALTITUDE]);

    this.fireAirspaceMoved(new AirspaceEditEvent(wwd, airspace, this));
  }