private Double[][] getValues(TileMatrix tileMatrix,
			TileResultSet tileResults, CoverageDataRequest request,
			int tileWidth, int tileHeight, int overlappingPixels) {

		Double[][] values = null;

		// Tiles are ordered by rows and then columns. Track the last column
		// coverage data of the tile to the left and the last rows of the tiles
		// in the row above
		Double[][] leftLastColumns = null;
		Map<Long, Double[][]> lastRowsByColumn = null;
		Map<Long, Double[][]> previousLastRowsByColumn = null;

		long previousRow = -1;
		long previousColumn = Long.MAX_VALUE;

		// Process each coverage data tile
		while (tileResults.moveToNext()) {

			// Get the next coverage data tile
			TileRow tileRow = tileResults.getRow();

			long currentRow = tileRow.getTileRow();
			long currentColumn = tileRow.getTileColumn();

			// If the row has changed, save off the previous last rows and begin
			// tracking this row. Clear the left last columns.
			if (currentRow > previousRow) {
				previousLastRowsByColumn = lastRowsByColumn;
				lastRowsByColumn = new HashMap<Long, Double[][]>();
				leftLastColumns = null;
			}

			// If there was a previous row, retrieve the top left and top
			// overlapping rows
			Double[][] topLeftRows = null;
			Double[][] topRows = null;
			if (previousLastRowsByColumn != null) {
				topLeftRows = previousLastRowsByColumn.get(currentColumn - 1);
				topRows = previousLastRowsByColumn.get(currentColumn);
			}

			// If the current column is not the column after the previous clear
			// the left values
			if (currentColumn < previousColumn
					|| currentColumn != previousColumn + 1) {
				leftLastColumns = null;
			}

			// Get the bounding box of the coverage data
			BoundingBox tileBoundingBox = TileBoundingBoxUtils.getBoundingBox(
					coverageBoundingBox, tileMatrix, currentColumn, currentRow);

			// Get the bounding box where the request and coverage data tile
			// overlap
			BoundingBox overlap = request.overlap(tileBoundingBox);

			// Get the gridded tile value for the tile
			GriddedTile griddedTile = getGriddedTile(tileRow.getId());

			// Get the coverage data tile image
			TImage image = createImage(tileRow);

			// If the tile overlaps with the requested box
			if (overlap != null) {

				// Get the rectangle of the tile coverage data with matching
				// values
				ImageRectangleF src = TileBoundingBoxJavaUtils
						.getFloatRectangle(tileMatrix.getTileWidth(),
								tileMatrix.getTileHeight(), tileBoundingBox,
								overlap);

				// Get the rectangle of where to store the results
				ImageRectangleF dest = null;
				if (request.getProjectedBoundingBox().equals(overlap)) {
					if (request.isPoint()) {
						// For single points request only a single destination
						// pixel
						dest = new ImageRectangleF(0, 0, 0, 0);
					} else {
						// The overlap is equal to the request, set as the full
						// destination size
						dest = new ImageRectangleF(0, 0, tileWidth, tileHeight);
					}
				} else {
					dest = TileBoundingBoxJavaUtils.getFloatRectangle(
							tileWidth, tileHeight,
							request.getProjectedBoundingBox(), overlap);
				}

				if (src.isValidAllowEmpty() && dest.isValidAllowEmpty()) {

					// Create the coverage data array first time through
					if (values == null) {
						values = new Double[tileHeight][tileWidth];
					}

					// Get the destination widths
					float destWidth = dest.getRight() - dest.getLeft();
					float destHeight = dest.getBottom() - dest.getTop();

					// Get the destination heights
					float srcWidth = src.getRight() - src.getLeft();
					float srcHeight = src.getBottom() - src.getTop();

					// Determine the source to destination ratio and how many
					// destination pixels equal half a source pixel
					float widthRatio;
					float halfDestWidthPixel;
					if (destWidth == 0) {
						widthRatio = 0.0f;
						halfDestWidthPixel = 0.0f;
					} else {
						widthRatio = srcWidth / destWidth;
						halfDestWidthPixel = 0.5f / widthRatio;
					}
					float heightRatio;
					float halfDestHeightPixel;
					if (destHeight == 0) {
						heightRatio = 0.0f;
						halfDestHeightPixel = 0.0f;
					} else {
						heightRatio = srcHeight / destHeight;
						halfDestHeightPixel = 0.5f / heightRatio;
					}

					float algorithmDestWidthPixelOverlap = halfDestWidthPixel
							* overlappingPixels;
					float algorithmDestHeightPixelOverlap = halfDestHeightPixel
							* overlappingPixels;

					// Determine the range of destination values to set
					int minDestY = (int) Math.floor(dest.getTop()
							- algorithmDestHeightPixelOverlap);
					int maxDestY = (int) Math.ceil(dest.getBottom()
							+ algorithmDestHeightPixelOverlap);
					int minDestX = (int) Math.floor(dest.getLeft()
							- algorithmDestWidthPixelOverlap);
					int maxDestX = (int) Math.ceil(dest.getRight()
							+ algorithmDestWidthPixelOverlap);
					minDestY = Math.max(minDestY, 0);
					minDestX = Math.max(minDestX, 0);
					maxDestY = Math.min(maxDestY, tileHeight - 1);
					maxDestX = Math.min(maxDestX, tileWidth - 1);

					// Read and set the coverage data values
					for (int y = minDestY; y <= maxDestY; y++) {
						for (int x = minDestX; x <= maxDestX; x++) {

							if (values[y][x] == null) {

								// Determine the coverage data based upon the
								// selected algorithm
								Double value = null;
								switch (algorithm) {
								case NEAREST_NEIGHBOR:
									value = getNearestNeighborValue(
											griddedTile, image,
											leftLastColumns, topLeftRows,
											topRows, y, x, widthRatio,
											heightRatio, dest.getTop(),
											dest.getLeft(), src.getTop(),
											src.getLeft());
									break;
								case BILINEAR:
									value = getBilinearInterpolationValue(
											griddedTile, image,
											leftLastColumns, topLeftRows,
											topRows, y, x, widthRatio,
											heightRatio, dest.getTop(),
											dest.getLeft(), src.getTop(),
											src.getLeft());
									break;
								case BICUBIC:
									value = getBicubicInterpolationValue(
											griddedTile, image,
											leftLastColumns, topLeftRows,
											topRows, y, x, widthRatio,
											heightRatio, dest.getTop(),
											dest.getLeft(), src.getTop(),
											src.getLeft());
									break;
								default:
									throw new UnsupportedOperationException(
											"Algorithm is not supported: "
													+ algorithm);
								}

								if (value != null) {
									values[y][x] = value;
								}

							}
						}
					}

				}
			}

			// Determine and store the coverage data of the last columns and
			// rows
			leftLastColumns = new Double[overlappingPixels][(int) tileMatrix
					.getTileHeight()];
			Double[][] lastRows = new Double[overlappingPixels][(int) tileMatrix
					.getTileWidth()];
			lastRowsByColumn.put(currentColumn, lastRows);

			// For each overlapping pixel
			for (int lastIndex = 0; lastIndex < overlappingPixels; lastIndex++) {

				// Store the last column row coverage data values
				int lastColumnIndex = (int) tileMatrix.getTileWidth()
						- lastIndex - 1;
				for (int row = 0; row < tileMatrix.getTileHeight(); row++) {
					Double value = getValue(griddedTile, image,
							lastColumnIndex, row);
					leftLastColumns[lastIndex][row] = value;
				}

				// Store the last row column coverage data values
				int lastRowIndex = (int) tileMatrix.getTileHeight() - lastIndex
						- 1;
				for (int column = 0; column < tileMatrix.getTileWidth(); column++) {
					Double value = getValue(griddedTile, image, column,
							lastRowIndex);
					lastRows[lastIndex][column] = value;
				}

			}

			// Update the previous row and column
			previousRow = currentRow;
			previousColumn = currentColumn;
		}

		return values;
	}
private Double [ ] [ ] getValues ( TileMatrix tileMatrix , TileResultSet tileResults , CoverageDataRequest request , int tileWidth , int tileHeight , int overlappingPixels ) { Double [ ] [ ] values = null ; Double [ ] [ ] leftLastColumns = null ; Map < Long , Double [ ] [ ] > lastRowsByColumn = null ; Map < Long , Double [ ] [ ] > previousLastRowsByColumn = null ; long previousRow = - 1 ; long previousColumn = Long . MAX_VALUE ; while ( tileResults . moveToNext ( ) ) { TileRow tileRow = tileResults . getRow ( ) ; long currentRow = tileRow . getTileRow ( ) ; long currentColumn = tileRow . getTileColumn ( ) ; if ( currentRow > previousRow ) { previousLastRowsByColumn = lastRowsByColumn ; lastRowsByColumn = new HashMap < Long , Double [ ] [ ] > ( ) ; leftLastColumns = null ; } Double [ ] [ ] topLeftRows = null ; Double [ ] [ ] topRows = null ; if ( previousLastRowsByColumn != null ) { topLeftRows = previousLastRowsByColumn . get ( currentColumn - 1 ) ; topRows = previousLastRowsByColumn . get ( currentColumn ) ; } if ( currentColumn < previousColumn || currentColumn != previousColumn + 1 ) { leftLastColumns = null ; } BoundingBox tileBoundingBox = TileBoundingBoxUtils . getBoundingBox ( coverageBoundingBox , tileMatrix , currentColumn , currentRow ) ; BoundingBox overlap = request . overlap ( tileBoundingBox ) ; GriddedTile griddedTile = getGriddedTile ( tileRow . getId ( ) ) ; TImage image = createImage ( tileRow ) ; if ( overlap != null ) { ImageRectangleF src = TileBoundingBoxJavaUtils . getFloatRectangle ( tileMatrix . getTileWidth ( ) , tileMatrix . getTileHeight ( ) , tileBoundingBox , overlap ) ; ImageRectangleF dest = null ; if ( request . getProjectedBoundingBox ( ) . equals ( overlap ) ) { if ( request . isPoint ( ) ) { dest = new ImageRectangleF ( 0 , 0 , 0 , 0 ) ; } else { dest = new ImageRectangleF ( 0 , 0 , tileWidth , tileHeight ) ; } } else { dest = TileBoundingBoxJavaUtils . getFloatRectangle ( tileWidth , tileHeight , request . getProjectedBoundingBox ( ) , overlap ) ; } if ( src . isValidAllowEmpty ( ) && dest . isValidAllowEmpty ( ) ) { if ( values == null ) { values = new Double [ tileHeight ] [ tileWidth ] ; } float destWidth = dest . getRight ( ) - dest . getLeft ( ) ; float destHeight = dest . getBottom ( ) - dest . getTop ( ) ; float srcWidth = src . getRight ( ) - src . getLeft ( ) ; float srcHeight = src . getBottom ( ) - src . getTop ( ) ; float widthRatio ; float halfDestWidthPixel ; if ( destWidth == 0 ) { widthRatio = 0.0f ; halfDestWidthPixel = 0.0f ; } else { widthRatio = srcWidth / destWidth ; halfDestWidthPixel = 0.5f / widthRatio ; } float heightRatio ; float halfDestHeightPixel ; if ( destHeight == 0 ) { heightRatio = 0.0f ; halfDestHeightPixel = 0.0f ; } else { heightRatio = srcHeight / destHeight ; halfDestHeightPixel = 0.5f / heightRatio ; } float algorithmDestWidthPixelOverlap = halfDestWidthPixel * overlappingPixels ; float algorithmDestHeightPixelOverlap = halfDestHeightPixel * overlappingPixels ; int minDestY = ( int ) Math . floor ( dest . getTop ( ) - algorithmDestHeightPixelOverlap ) ; int maxDestY = ( int ) Math . ceil ( dest . getBottom ( ) + algorithmDestHeightPixelOverlap ) ; int minDestX = ( int ) Math . floor ( dest . getLeft ( ) - algorithmDestWidthPixelOverlap ) ; int maxDestX = ( int ) Math . ceil ( dest . getRight ( ) + algorithmDestWidthPixelOverlap ) ; minDestY = Math . max ( minDestY , 0 ) ; minDestX = Math . max ( minDestX , 0 ) ; maxDestY = Math . min ( maxDestY , tileHeight - 1 ) ; maxDestX = Math . min ( maxDestX , tileWidth - 1 ) ; for ( int y = minDestY ; y <= maxDestY ; y ++ ) { for ( int x = minDestX ; x <= maxDestX ; x ++ ) { if ( values [ y ] [ x ] == null ) { Double value = null ; switch ( algorithm ) { case NEAREST_NEIGHBOR : value = getNearestNeighborValue ( griddedTile , image , leftLastColumns , topLeftRows , topRows , y , x , widthRatio , heightRatio , dest . getTop ( ) , dest . getLeft ( ) , src . getTop ( ) , src . getLeft ( ) ) ; break ; case BILINEAR : value = getBilinearInterpolationValue ( griddedTile , image , leftLastColumns , topLeftRows , topRows , y , x , widthRatio , heightRatio , dest . getTop ( ) , dest . getLeft ( ) , src . getTop ( ) , src . getLeft ( ) ) ; break ; case BICUBIC : value = getBicubicInterpolationValue ( griddedTile , image , leftLastColumns , topLeftRows , topRows , y , x , widthRatio , heightRatio , dest . getTop ( ) , dest . getLeft ( ) , src . getTop ( ) , src . getLeft ( ) ) ; break ; default : throw new UnsupportedOperationException ( "Algorithm is not supported: " + algorithm ) ; } if ( value != null ) { values [ y ] [ x ] = value ; } } } } } } leftLastColumns = new Double [ overlappingPixels ] [ ( int ) tileMatrix . getTileHeight ( ) ] ; Double [ ] [ ] lastRows = new Double [ overlappingPixels ] [ ( int ) tileMatrix . getTileWidth ( ) ] ; lastRowsByColumn . put ( currentColumn , lastRows ) ; for ( int lastIndex = 0 ; lastIndex < overlappingPixels ; lastIndex ++ ) { int lastColumnIndex = ( int ) tileMatrix . getTileWidth ( ) - lastIndex - 1 ; for ( int row = 0 ; row < tileMatrix . getTileHeight ( ) ; row ++ ) { Double value = getValue ( griddedTile , image , lastColumnIndex , row ) ; leftLastColumns [ lastIndex ] [ row ] = value ; } int lastRowIndex = ( int ) tileMatrix . getTileHeight ( ) - lastIndex - 1 ; for ( int column = 0 ; column < tileMatrix . getTileWidth ( ) ; column ++ ) { Double value = getValue ( griddedTile , image , column , lastRowIndex ) ; lastRows [ lastIndex ] [ column ] = value ; } } previousRow = currentRow ; previousColumn = currentColumn ; } return values ; }
Get the coverage data values from the tile results scaled to the provided
dimensions

@param tileMatrix
tile matrix
@param tileResults
tile results
@param request
coverage data request
@param tileWidth
tile width
@param tileHeight
tile height
@param overlappingPixels
overlapping request pixels
@return coverage data values