@Override
  protected List<Vec4> computeMinimalGeometry(Globe globe, double verticalExaggeration) {
    double[] angles = this.computeAngles();
    // Angles are equal, fall back to building a closed cylinder.
    if (angles == null) return super.computeMinimalGeometry(globe, verticalExaggeration);

    double[] radii = this.getRadii();
    Matrix transform = this.computeTransform(globe, verticalExaggeration);

    GeometryBuilder gb = this.getGeometryBuilder();
    int count = gb.getPartialDiskVertexCount(MINIMAL_GEOMETRY_SLICES, MINIMAL_GEOMETRY_LOOPS);
    int numCoords = 3 * count;
    float[] verts = new float[numCoords];
    gb.makePartialDiskVertices(
        (float) radii[0],
        (float) radii[1], // Inner radius, outer radius.
        MINIMAL_GEOMETRY_SLICES,
        MINIMAL_GEOMETRY_LOOPS, // Slices, loops,
        (float) angles[0],
        (float) angles[2], // Start angle, sweep angle.
        verts);

    List<LatLon> locations = new ArrayList<LatLon>();
    for (int i = 0; i < numCoords; i += 3) {
      Vec4 v = new Vec4(verts[i], verts[i + 1], verts[i + 2]);
      v = v.transformBy4(transform);
      locations.add(globe.computePositionFromPoint(v));
    }

    ArrayList<Vec4> points = new ArrayList<Vec4>();
    this.makeExtremePoints(globe, verticalExaggeration, locations, points);

    return points;
  }
  private void makeRadialWallTerrainConformant(
      DrawContext dc,
      int pillars,
      int stacks,
      float[] verts,
      double[] altitudes,
      boolean[] terrainConformant,
      Vec4 referenceCenter) {
    Globe globe = dc.getGlobe();
    Matrix transform = this.computeTransform(dc.getGlobe(), dc.getVerticalExaggeration());

    for (int p = 0; p <= pillars; p++) {
      int index = p;
      index = 3 * index;
      Vec4 vec = new Vec4(verts[index], verts[index + 1], verts[index + 2]);
      vec = vec.transformBy4(transform);
      Position pos = globe.computePositionFromPoint(vec);

      for (int s = 0; s <= stacks; s++) {
        double elevation = altitudes[s];
        if (terrainConformant[s])
          elevation += this.computeElevationAt(dc, pos.getLatitude(), pos.getLongitude());
        vec = globe.computePointFromPosition(pos.getLatitude(), pos.getLongitude(), elevation);

        index = p + s * (pillars + 1);
        index = 3 * index;
        verts[index] = (float) (vec.x - referenceCenter.x);
        verts[index + 1] = (float) (vec.y - referenceCenter.y);
        verts[index + 2] = (float) (vec.z - referenceCenter.z);
      }
    }
  }
  private void makePartialDiskTerrainConformant(
      DrawContext dc,
      int numCoords,
      float[] verts,
      double altitude,
      boolean terrainConformant,
      Vec4 referenceCenter) {
    Globe globe = dc.getGlobe();
    Matrix transform = this.computeTransform(dc.getGlobe(), dc.getVerticalExaggeration());

    for (int i = 0; i < numCoords; i += 3) {
      Vec4 vec = new Vec4(verts[i], verts[i + 1], verts[i + 2]);
      vec = vec.transformBy4(transform);
      Position p = globe.computePositionFromPoint(vec);

      double elevation = altitude;
      if (terrainConformant)
        elevation += this.computeElevationAt(dc, p.getLatitude(), p.getLongitude());

      vec = globe.computePointFromPosition(p.getLatitude(), p.getLongitude(), elevation);
      verts[i] = (float) (vec.x - referenceCenter.x);
      verts[i + 1] = (float) (vec.y - referenceCenter.y);
      verts[i + 2] = (float) (vec.z - referenceCenter.z);
    }
  }
  private void makePartialCylinderTerrainConformant(
      DrawContext dc,
      int slices,
      int stacks,
      float[] verts,
      double[] altitudes,
      boolean[] terrainConformant,
      Vec4 referenceCenter) {
    Globe globe = dc.getGlobe();
    Matrix transform = this.computeTransform(dc.getGlobe(), dc.getVerticalExaggeration());

    for (int i = 0; i <= slices; i++) {
      int index = i * (stacks + 1);
      index = 3 * index;
      Vec4 vec = new Vec4(verts[index], verts[index + 1], verts[index + 2]);
      vec = vec.transformBy4(transform);
      Position p = globe.computePositionFromPoint(vec);

      for (int j = 0; j <= stacks; j++) {
        double elevation = altitudes[j];
        if (terrainConformant[j])
          elevation += this.computeElevationAt(dc, p.getLatitude(), p.getLongitude());
        vec = globe.computePointFromPosition(p.getLatitude(), p.getLongitude(), elevation);

        index = j + i * (stacks + 1);
        index = 3 * index;
        verts[index] = (float) (vec.x - referenceCenter.x);
        verts[index + 1] = (float) (vec.y - referenceCenter.y);
        verts[index + 2] = (float) (vec.z - referenceCenter.z);
      }
    }
  }
  private void makeCap(
      DrawContext dc,
      GeometryBuilder.IndexedTriangleArray ita,
      double altitude,
      boolean terrainConformant,
      int orientation,
      Matrix locationTransform,
      Vec4 referenceCenter,
      int indexPos,
      int[] indices,
      int vertexPos,
      float[] vertices,
      float[] normals) {
    GeometryBuilder gb = this.getGeometryBuilder();
    Globe globe = dc.getGlobe();

    int indexCount = ita.getIndexCount();
    int vertexCount = ita.getVertexCount();
    int[] locationIndices = ita.getIndices();
    float[] locationVerts = ita.getVertices();

    this.copyIndexArray(
        indexCount,
        (orientation == GeometryBuilder.INSIDE),
        locationIndices,
        vertexPos,
        indexPos,
        indices);

    for (int i = 0; i < vertexCount; i++) {
      int index = 3 * i;
      Vec4 vec = new Vec4(locationVerts[index], locationVerts[index + 1], locationVerts[index + 2]);
      vec = vec.transformBy4(locationTransform);

      Position pos = globe.computePositionFromPoint(vec);
      vec =
          this.computePointFromPosition(
              dc, pos.getLatitude(), pos.getLongitude(), altitude, terrainConformant);

      index = 3 * (vertexPos + i);
      vertices[index] = (float) (vec.x - referenceCenter.x);
      vertices[index + 1] = (float) (vec.y - referenceCenter.y);
      vertices[index + 2] = (float) (vec.z - referenceCenter.z);
    }

    gb.makeIndexedTriangleArrayNormals(
        indexPos, indexCount, indices, vertexPos, vertexCount, vertices, normals);
  }
  private void makeSectionVertices(
      DrawContext dc,
      int locationPos,
      float[] locations,
      double[] altitude,
      boolean[] terrainConformant,
      int subdivisions,
      Matrix locationTransform,
      Vec4 referenceCenter,
      int vertexPos,
      float[] vertices) {
    GeometryBuilder gb = this.getGeometryBuilder();
    int numPoints = gb.getSubdivisionPointsVertexCount(subdivisions);

    Globe globe = dc.getGlobe();
    int index1 = 3 * locationPos;
    int index2 = 3 * (locationPos + 1);

    float[] locationVerts = new float[3 * numPoints];
    gb.makeSubdivisionPoints(
        locations[index1],
        locations[index1 + 1],
        locations[index1 + 2],
        locations[index2],
        locations[index2 + 1],
        locations[index2 + 2],
        subdivisions,
        locationVerts);

    for (int i = 0; i < numPoints; i++) {
      int index = 3 * i;
      Vec4 vec = new Vec4(locationVerts[index], locationVerts[index + 1], locationVerts[index + 2]);
      vec = vec.transformBy4(locationTransform);
      Position pos = globe.computePositionFromPoint(vec);

      for (int j = 0; j < 2; j++) {
        vec =
            this.computePointFromPosition(
                dc, pos.getLatitude(), pos.getLongitude(), altitude[j], terrainConformant[j]);

        index = 2 * i + j;
        index = 3 * (vertexPos + index);
        vertices[index] = (float) (vec.x - referenceCenter.x);
        vertices[index + 1] = (float) (vec.y - referenceCenter.y);
        vertices[index + 2] = (float) (vec.z - referenceCenter.z);
      }
    }
  }