protected Vec4 computeAnnotationPosition(Position pos) {
    Vec4 surfacePoint =
        this.wwd
            .getSceneController()
            .getTerrain()
            .getSurfacePoint(pos.getLatitude(), pos.getLongitude());
    if (surfacePoint == null) {
      Globe globe = this.wwd.getModel().getGlobe();
      surfacePoint =
          globe.computePointFromPosition(
              pos.getLatitude(),
              pos.getLongitude(),
              globe.getElevation(pos.getLatitude(), pos.getLongitude()));
    }

    return this.wwd.getView().project(surfacePoint);
  }
  protected void assembleVertexControlPoints(DrawContext dc) {
    Terrain terrain = dc.getTerrain();
    ExtrudedPolygon polygon = this.getPolygon();

    Position refPos = polygon.getReferencePosition();
    Vec4 refPoint = terrain.getSurfacePoint(refPos.getLatitude(), refPos.getLongitude(), 0);

    int altitudeMode = polygon.getAltitudeMode();
    double height = polygon.getHeight();

    Vec4 vaa = null;
    double vaaLength = 0; // used to compute independent length of each cap vertex
    double vaLength = 0;

    int i = 0;
    for (LatLon location : polygon.getOuterBoundary()) {
      Vec4 vert;

      // Compute the top/cap point.
      if (altitudeMode == WorldWind.CONSTANT || !(location instanceof Position)) {
        if (vaa == null) {
          // Compute the vector lengths of the top and bottom points at the reference position.
          vaa = refPoint.multiply3(height / refPoint.getLength3());
          vaaLength = vaa.getLength3();
          vaLength = refPoint.getLength3();
        }

        // Compute the bottom point, which is on the terrain.
        vert = terrain.getSurfacePoint(location.getLatitude(), location.getLongitude(), 0);

        double delta = vaLength - vert.dot3(refPoint) / vaLength;
        vert = vert.add3(vaa.multiply3(1d + delta / vaaLength));
      } else if (altitudeMode == WorldWind.RELATIVE_TO_GROUND) {
        vert =
            terrain.getSurfacePoint(
                location.getLatitude(),
                location.getLongitude(),
                ((Position) location).getAltitude());
      } else // WorldWind.ABSOLUTE
      {
        vert =
            terrain
                .getGlobe()
                .computePointFromPosition(
                    location.getLatitude(),
                    location.getLongitude(),
                    ((Position) location).getAltitude() * terrain.getVerticalExaggeration());
      }

      Position vertexPosition = this.wwd.getModel().getGlobe().computePositionFromPoint(vert);

      this.controlPoints.add(
          new ControlPointMarker(
              MOVE_VERTEX_ACTION, vertexPosition, vert, this.vertexControlAttributes, i));
      i++;
    }
  }
  protected String formatMeasurements(Position pos) {
    StringBuilder sb = new StringBuilder();

    /*
     //sb.append(this.unitsFormat.areaNL(this.getLabel(AREA_LABEL), this.getArea()));
     sb.append(this.unitsFormat.lengthNL(this.getLabel(PERIMETER_LABEL), this.getLength()));
    */

    // sb.append(this.unitsFormat.lengthNL(this.getLabel(WIDTH_LABEL),
    // this.shape.getEastWestRadius() * 2));
    // sb.append(this.unitsFormat.lengthNL(this.getLabel(LENGTH_LABEL),
    // this.shape.getNorthSouthRadius() * 2));
    // sb.append(this.unitsFormat.lengthNL(this.getLabel(HEIGHT_LABEL),
    // this.shape.getVerticalRadius() * 2));

    // sb.append(this.unitsFormat.angleNL(this.getLabel(HEADING_LABEL), this.shape.getHeading()));

    // if "activeControlPoint" is in fact one of the control points
    if (!this.arePositionsRedundant(pos, this.polygon.getReferencePosition())) {
      sb.append(this.unitsFormat.angleNL(this.getLabel(LATITUDE_LABEL), pos.getLatitude()));
      sb.append(this.unitsFormat.angleNL(this.getLabel(LONGITUDE_LABEL), pos.getLongitude()));
      sb.append(this.unitsFormat.lengthNL(this.getLabel(ALTITUDE_LABEL), pos.getAltitude()));
    }

    // if "activeControlPoint" is the shape itself
    if (this.polygon.getReferencePosition() != null) {
      sb.append(
          this.unitsFormat.angleNL(
              this.getLabel(CENTER_LATITUDE_LABEL),
              this.polygon.getReferencePosition().getLatitude()));
      sb.append(
          this.unitsFormat.angleNL(
              this.getLabel(CENTER_LONGITUDE_LABEL),
              this.polygon.getReferencePosition().getLongitude()));
      sb.append(
          this.unitsFormat.lengthNL(
              this.getLabel(CENTER_ALTITUDE_LABEL),
              this.polygon.getReferencePosition().getAltitude()));
    }

    return sb.toString();
  }
  protected void setPolygonHeight(Point previousMousePoint, Point mousePoint) {
    // 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 polygon height.

    Position referencePos = this.polygon.getReferencePosition();
    if (referencePos == null) return;

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

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

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

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

    java.util.List<Position> boundary = new ArrayList<Position>();
    for (LatLon ll : this.polygon.getOuterBoundary()) {
      boundary.add(new Position(ll, ((Position) ll).getElevation() + elevationChange));
    }

    this.polygon.setOuterBoundary(boundary);
  }