class AbstractGeographicProjection extends AbstractProjection {

    protected TesseraList<GeographicProjectedTesseraVertex> quadTessellate(GeographicPosition vert1, GeographicPosition vert2,
            GeographicPosition vert3, GeographicPosition vert4, int xSplits, int ySplits, Vector3d modelCenter)
    {
        int rows = ySplits + 2;
        int cols = xSplits + 2;
        int cells = rows * cols;
        LatLonAlt[] grid = new LatLonAlt[cells];
        int lastColIndex = rows * (cols - 1);
        LatLonAlt llaVert1 = vert1.getLatLonAlt();
        LatLonAlt llaVert2 = vert2.getLatLonAlt();
        LatLonAlt llaVert3 = vert3.getLatLonAlt();
        LatLonAlt llaVert4 = vert4.getLatLonAlt();
        for (int j = 0; j < rows; j++)
        {
            grid[j] = llaVert1.interpolate(llaVert4, (double)j / (rows - 1));
            grid[j + lastColIndex] = llaVert2.interpolate(llaVert3, (double)j / (rows - 1));
        }

        for (int i = 1; i < cols - 1; i++)
        {
            for (int j = 0; j < rows; j++)
            {
                LatLonAlt vert = grid[j].interpolate(grid[j + lastColIndex], (double)i / (cols - 1));
                grid[j + i * rows] = vert;
            }
        }

        List<GeographicTesseraVertex> vertices = New.list(cells);
        for (int ix = 0; ix < cells; ix++)
        {
            GeographicPosition geoPos = new GeographicPosition(grid[ix]);
            Vector3d vec = convertToModel(geoPos, modelCenter);
            vertices.add(new GeographicTesseraVertex(geoPos, vec));
        }

        PetrifyableTIntList indices = new PetrifyableTIntArrayList(cells * 4);
        for (int i = 0; i < cols - 1; i++)
        {
            for (int j = 0; j < rows - 1; j++)
            {
                indices.add(j + i * rows);
                indices.add(j + (i + 1) * rows);
                indices.add(j + (i + 1) * rows + 1);
                indices.add(j + i * rows + 1);
            }
        }
        return new TesseraList<>(vertices, indices, 4, false);
    }

}