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++;
    }
  }
  /**
   * Compute points on either side of a line segment. This method requires a point on the line, and
   * either a next point, previous point, or both.
   *
   * @param point Center point about which to compute side points.
   * @param prev Previous point on the line. May be null if {@code next} is non-null.
   * @param next Next point on the line. May be null if {@code prev} is non-null.
   * @param leftPositions Left position will be added to this list.
   * @param rightPositions Right position will be added to this list.
   * @param halfWidth Distance from the center line to the left or right lines.
   * @param globe Current globe.
   */
  protected void generateParallelPoints(
      Vec4 point,
      Vec4 prev,
      Vec4 next,
      List<Position> leftPositions,
      List<Position> rightPositions,
      double halfWidth,
      Globe globe) {
    if ((point == null) || (prev == null && next == null)) {
      String message = Logging.getMessage("nullValue.PointIsNull");
      Logging.logger().severe(message);
      throw new IllegalArgumentException(message);
    }
    if (leftPositions == null || rightPositions == null) {
      String message = Logging.getMessage("nullValue.PositionListIsNull");
      Logging.logger().severe(message);
      throw new IllegalArgumentException(message);
    }
    if (globe == null) {
      String message = Logging.getMessage("nullValue.GlobeIsNull");
      Logging.logger().severe(message);
      throw new IllegalArgumentException(message);
    }

    Vec4 offset;
    Vec4 normal = globe.computeSurfaceNormalAtPoint(point);

    // Compute vector in the direction backward along the line.
    Vec4 backward = (prev != null) ? prev.subtract3(point) : point.subtract3(next);

    // Compute a vector perpendicular to segment BC, and the globe normal vector.
    Vec4 perpendicular = backward.cross3(normal);

    double length;
    // If both next and previous points are supplied then calculate the angle that bisects the angle
    // current, next, prev.
    if (next != null && prev != null && !Vec4.areColinear(prev, point, next)) {
      // Compute vector in the forward direction.
      Vec4 forward = next.subtract3(point);

      // Calculate the vector that bisects angle ABC.
      offset = forward.normalize3().add3(backward.normalize3());
      offset = offset.normalize3();

      // Compute the scalar triple product of the vector BC, the normal vector, and the offset
      // vector to
      // determine if the offset points to the left or the right of the control line.
      double tripleProduct = perpendicular.dot3(offset);
      if (tripleProduct < 0) {
        offset = offset.multiply3(-1);
      }

      // Determine the length of the offset vector that will keep the left and right lines parallel
      // to the control
      // line.
      Angle theta = backward.angleBetween3(offset);
      if (!Angle.ZERO.equals(theta)) length = halfWidth / theta.sin();
      else length = halfWidth;
    } else {
      offset = perpendicular.normalize3();
      length = halfWidth;
    }
    offset = offset.multiply3(length);

    // Determine the left and right points by applying the offset.
    Vec4 ptRight = point.add3(offset);
    Vec4 ptLeft = point.subtract3(offset);

    // Convert cartesian points to geographic.
    Position posLeft = globe.computePositionFromPoint(ptLeft);
    Position posRight = globe.computePositionFromPoint(ptRight);

    leftPositions.add(posLeft);
    rightPositions.add(posRight);
  }
  protected Vec4[] calculateBentNormals(int width, int height, Vec4[] verts, int padding) {
    int padding2 = padding * 2;

    if (verts.length != (width + padding2) * (height + padding2))
      throw new IllegalStateException("Illegal vertices length");

    Vec4[] norms = new Vec4[width * height];

    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        Vec4 vec =
            verts[getArrayIndex(width + padding2, height + padding2, x + padding, y + padding)];
        if (vec != null) {
          Vec4 vecnorm = vec.normalize3();
          Vec4[] maxes = new Vec4[16];
          double[] angles = new double[16];
          for (int i = 0; i < angles.length; i++) {
            angles[i] = Double.MAX_VALUE;
          }

          //  2  3  4  5  6
          //  1           7
          //  0           8
          // 15           9
          // 14 13 12 11 10

          // for (int i = 1; i <= padding; i++)
          for (int i = 2; i <= padding; i += 2) {
            Vec4[] vecs = new Vec4[16];
            vecs[0] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding - i, y + padding)];
            vecs[2] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding - i, y + padding - i)];
            vecs[4] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding, y + padding - i)];
            vecs[6] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding + i, y + padding - i)];
            vecs[8] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding + i, y + padding)];
            vecs[10] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding + i, y + padding + i)];
            vecs[12] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding, y + padding + i)];
            vecs[14] =
                verts[
                    getArrayIndex(
                        width + padding2, height + padding2, x + padding - i, y + padding + i)];
            if (i % 2 == 0) {
              int i2 = i / 2;
              vecs[1] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding - i, y + padding - i2)];
              vecs[3] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding - i2, y + padding - i)];
              vecs[5] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding + i2, y + padding - i)];
              vecs[7] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding + i, y + padding - i2)];
              vecs[9] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding + i, y + padding + i2)];
              vecs[11] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding + i2, y + padding + i)];
              vecs[13] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding - i2, y + padding + i)];
              vecs[15] =
                  verts[
                      getArrayIndex(
                          width + padding2, height + padding2, x + padding - i, y + padding + i2)];
            }

            for (int j = 0; j < maxes.length; j++) {
              if (vecs[j] != null) {
                Vec4 v = vecs[j].subtract3(vec).normalize3();
                double angle = Math.acos(v.dot3(vecnorm));
                if (angle < angles[j]) {
                  angles[j] = angle;
                  maxes[j] = v;
                }
              }
            }
          }

          Vec4 normal = Vec4.ZERO;
          for (int i = 0; i < maxes.length; i++) {
            if (maxes[i] != null) {
              Vec4 n = maxes[i].cross3(vecnorm).cross3(maxes[i]);
              normal = normal.add3(n);
            }
          }
          if (normal != Vec4.ZERO) {
            norms[getArrayIndex(width, height, x, y)] = normal.normalize3();
          }
        }
      }
    }

    return norms;
  }