public MeshTile[] subdivide(Level nextLevel) {
      Angle p0 = this.getSector().getMinLatitude();
      Angle p2 = this.getSector().getMaxLatitude();
      Angle p1 = Angle.midAngle(p0, p2);

      Angle t0 = this.getSector().getMinLongitude();
      Angle t2 = this.getSector().getMaxLongitude();
      Angle t1 = Angle.midAngle(t0, t2);

      int row = this.getRow();
      int col = this.getColumn();

      MeshCoords[] coords = this.coords.subdivide();

      MeshTile[] subTiles = new MeshTile[4];
      subTiles[0] =
          new MeshTile(
              new Sector(p0, p1, t0, t1),
              nextLevel,
              2 * row,
              2 * col,
              coords[0]); // Lower left quadrant.
      subTiles[1] =
          new MeshTile(
              new Sector(p0, p1, t1, t2),
              nextLevel,
              2 * row,
              2 * col + 1,
              coords[1]); // Lower right quadrant.
      subTiles[2] =
          new MeshTile(
              new Sector(p1, p2, t1, t2),
              nextLevel,
              2 * row + 1,
              2 * col + 1,
              coords[2]); // Upper right quadrant
      subTiles[3] =
          new MeshTile(
              new Sector(p1, p2, t0, t1),
              nextLevel,
              2 * row + 1,
              2 * col,
              coords[3]); // Upper left quadrant.
      return subTiles;
    }
  protected Angle computeIconRadius(DrawContext dc, double regionPixelSize, Sector drawSector) {
    double minCosLat =
        Math.min(drawSector.getMinLatitude().cos(), drawSector.getMaxLatitude().cos());
    if (minCosLat < 0.001) return Angle.POS180;

    Rectangle2D iconDimension = this.computeDrawDimension(regionPixelSize); // Meter
    double dLat = iconDimension.getHeight() / dc.getGlobe().getRadius();
    double dLon = iconDimension.getWidth() / dc.getGlobe().getRadius() / minCosLat;
    return Angle.fromRadians(Math.sqrt(dLat * dLat + dLon * dLon) / 2);
  }
  private static MeshTile[] createTiles(LevelSet levelSet, int levelNumber, MeshCoords coords) {
    Sector sector = levelSet.getSector();
    Level level = levelSet.getLevel(levelNumber);
    Angle dLat = level.getTileDelta().getLatitude();
    Angle dLon = level.getTileDelta().getLongitude();
    Angle latOrigin = levelSet.getTileOrigin().getLatitude();
    Angle lonOrigin = levelSet.getTileOrigin().getLongitude();

    // Determine the row and column offset from the common World Wind global tiling origin.
    int firstRow = Tile.computeRow(dLat, sector.getMinLatitude(), latOrigin);
    int firstCol = Tile.computeColumn(dLon, sector.getMinLongitude(), lonOrigin);
    int lastRow = Tile.computeRow(dLat, sector.getMaxLatitude(), latOrigin);
    int lastCol = Tile.computeColumn(dLon, sector.getMaxLongitude(), lonOrigin);

    int numLatTiles = lastRow - firstRow + 1;
    int numLonTiles = lastCol - firstCol + 1;

    AffineTransform sectorTransform = createTransform(sector, coords);

    MeshTile[] tiles = new MeshTile[numLatTiles * numLonTiles];
    int index = 0;

    Angle p1 = Tile.computeRowLatitude(firstRow, dLat, latOrigin);

    for (int row = firstRow; row <= lastRow; row++) {
      Angle p2 = p1.add(dLat);

      Angle t1 = Tile.computeColumnLongitude(firstCol, dLon, lonOrigin);

      for (int col = firstCol; col <= lastCol; col++) {
        Angle t2 = t1.add(dLon);

        Sector tileSector = new Sector(p1, p2, t1, t2);
        MeshCoords tileCoords = transformSector(sectorTransform, tileSector);
        tiles[index++] = new MeshTile(tileSector, level, row, col, tileCoords);

        t1 = t2;
      }
      p1 = p2;
    }

    return tiles;
  }
  private void createTopLevelTiles() {
    MercatorSector sector = (MercatorSector) this.levels.getSector();

    Level level = levels.getFirstLevel();
    Angle dLat = level.getTileDelta().getLatitude();
    Angle dLon = level.getTileDelta().getLongitude();

    Angle latOrigin = this.levels.getTileOrigin().getLatitude();
    Angle lonOrigin = this.levels.getTileOrigin().getLongitude();

    // Determine the row and column offset from the common World Wind global tiling origin.
    int firstRow = Tile.computeRow(dLat, sector.getMinLatitude(), latOrigin);
    int firstCol = Tile.computeColumn(dLon, sector.getMinLongitude(), lonOrigin);
    int lastRow = Tile.computeRow(dLat, sector.getMaxLatitude(), latOrigin);
    int lastCol = Tile.computeColumn(dLon, sector.getMaxLongitude(), lonOrigin);

    int nLatTiles = lastRow - firstRow + 1;
    int nLonTiles = lastCol - firstCol + 1;

    this.topLevels = new ArrayList<MercatorTextureTile>(nLatTiles * nLonTiles);

    // Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
    double deltaLat = dLat.degrees / 90;
    double d1 = -1.0 + deltaLat * firstRow;
    for (int row = firstRow; row <= lastRow; row++) {
      // Angle p2;
      // p2 = p1.add(dLat);
      double d2 = d1 + deltaLat;

      Angle t1 = Tile.computeColumnLongitude(firstCol, dLon, lonOrigin);
      for (int col = firstCol; col <= lastCol; col++) {
        Angle t2;
        t2 = t1.add(dLon);

        this.topLevels.add(
            new MercatorTextureTile(new MercatorSector(d1, d2, t1, t2), level, row, col));
        t1 = t2;
      }
      d1 = d2;
    }
  }
  /**
   * Compute the amount of rotation to apply to a label in order to keep it oriented toward its
   * orientation position.
   *
   * @param screenPoint Geographic position of the text, projected onto the screen.
   * @param orientationScreenPoint Orientation position, projected onto the screen.
   * @return The rotation angle to apply when drawing the label.
   */
  protected Angle computeRotation(Vec4 screenPoint, Vec4 orientationScreenPoint) {
    // Determine delta between the orientation position and the label position
    double deltaX = screenPoint.x - orientationScreenPoint.x;
    double deltaY = screenPoint.y - orientationScreenPoint.y;

    if (deltaX != 0) {
      double angle = Math.atan(deltaY / deltaX);
      return Angle.fromRadians(angle);
    } else {
      return Angle.POS90; // Vertical label
    }
  }
 protected Angle computeSafeRadius(DrawContext dc, SurfaceTileDrawContext sdc) {
   double regionPixelSize = this.computeDrawPixelSize(dc, sdc);
   Angle sectorRadius = this.computeSectorRadius(sdc.getSector());
   Angle iconRadius = this.computeIconRadius(dc, regionPixelSize, sdc.getSector());
   return sectorRadius.add(iconRadius);
 }
 protected Angle computeSectorRadius(Sector sector) {
   double dLat = sector.getDeltaLatRadians();
   double dLon = sector.getDeltaLonRadians();
   return Angle.fromRadians(Math.sqrt(dLat * dLat + dLon * dLon) / 2);
 }