41 |
41 |
import org.gvsig.raster.cache.tile.Tile;
|
42 |
42 |
import org.gvsig.raster.impl.DefaultRasterManager;
|
43 |
43 |
import org.gvsig.raster.impl.datastruct.ExtentImpl;
|
|
44 |
import org.slf4j.Logger;
|
|
45 |
import org.slf4j.LoggerFactory;
|
44 |
46 |
|
45 |
47 |
/**
|
46 |
48 |
* Buffer composed by a list of tiles and its extents.
|
... | ... | |
50 |
52 |
* @author Nacho Brodin (nachobrodin@gmail.com)
|
51 |
53 |
*/
|
52 |
54 |
public class MemoryMatrixBuffer {
|
53 |
|
private Buffer[] bufferList = null;
|
54 |
|
private Buffer[] transpList = null;
|
55 |
|
private int nRows = 0;
|
56 |
|
private int nCols = 0;
|
|
55 |
private Logger log = LoggerFactory.getLogger(MemoryMatrixBuffer.class);
|
|
56 |
private Buffer[] bufferList = null;
|
|
57 |
private Position[] positionList = null;
|
|
58 |
private Buffer[] transpList = null;
|
|
59 |
private int nRows = 0;
|
|
60 |
private int nCols = 0;
|
57 |
61 |
@SuppressWarnings("unused")
|
58 |
|
private Extent bbox = null;
|
59 |
|
private List<Tile> tileList = null;
|
|
62 |
private Extent bbox = null;
|
|
63 |
private List<Tile> tileList = null;
|
60 |
64 |
|
|
65 |
public class Position {
|
|
66 |
int col = 0;
|
|
67 |
int row = 0;
|
|
68 |
}
|
|
69 |
|
61 |
70 |
/**
|
62 |
71 |
* Constructor using an array of tiles. It will compute the number
|
63 |
72 |
* of rows and columns and the complete bounding box
|
... | ... | |
243 |
252 |
|
244 |
253 |
/**
|
245 |
254 |
* Gets a window from tiles
|
246 |
|
* @param ext
|
|
255 |
* @param requestExtent
|
247 |
256 |
* @param buf
|
248 |
257 |
* @return
|
249 |
258 |
*/
|
250 |
|
public Buffer getWindow(Extent ext, Buffer buf, boolean alpha) {
|
|
259 |
public Buffer getWindow(Extent requestExtent, Buffer buf, boolean alpha) {
|
251 |
260 |
if(tileList.size() <= 0)
|
252 |
261 |
return null;
|
253 |
262 |
|
254 |
|
Buffer sourceWithoutResampling = createBufferWithoutResampling(ext, buf, tileList.get(0).getExtent(), bufferList[0]);
|
|
263 |
Buffer sourceWithoutResampling = createBufferWithoutResampling(requestExtent, buf, tileList.get(0).getExtent(), bufferList[0]);
|
|
264 |
double wcX1 = -1;
|
|
265 |
double wcY1 = -1;
|
|
266 |
int initXPxBuf = 0;
|
|
267 |
int initYPxBuf = 0;
|
|
268 |
|
255 |
269 |
for (int i = 0; i < bufferList.length; i++) {
|
|
270 |
|
256 |
271 |
//1-Calcular las coordenadas pixel del tile de entrada
|
257 |
|
int[] points = getClipPoints(tileList.get(i).getExtent(), bufferList[i], ext);
|
258 |
|
|
|
272 |
Rectangle2D rTile = getClipPoints(tileList.get(i).getExtent(), bufferList[i], requestExtent);
|
|
273 |
|
259 |
274 |
//2-Ajustar peti?n al extent del tile
|
260 |
|
Extent adjustedRequestExtent = getAdjustedExtent(tileList.get(i).getExtent(), ext);
|
261 |
|
|
262 |
|
if((points[0] == 0 && points[1] == 0) || (points[2] == 0 && points[3] == 0))
|
|
275 |
Extent adjustedRequestExtent = getAdjustedExtent(tileList.get(i).getExtent(), requestExtent);
|
|
276 |
|
|
277 |
if( (rTile.getX() == 0 && rTile.getWidth() == 0) ||
|
|
278 |
(rTile.getY() == 0 && rTile.getHeight() == 0))
|
263 |
279 |
continue;
|
264 |
280 |
|
265 |
281 |
//3-Calcular coordenada pixel de inicio del buffer
|
266 |
|
double wcX1 = Math.abs(adjustedRequestExtent.getMin().getX() - ext.getMin().getX());
|
267 |
|
double wcY1 = Math.abs(ext.getMax().getY() - adjustedRequestExtent.getMax().getY());
|
268 |
|
int initXPxBuf = (int)Math.round((wcX1 * (sourceWithoutResampling.getWidth())) / ext.width());
|
269 |
|
int initYPxBuf = (int)Math.round((wcY1 * (sourceWithoutResampling.getHeight())) / ext.height());
|
|
282 |
wcX1 = Math.abs(adjustedRequestExtent.getMin().getX() - requestExtent.getMin().getX());
|
|
283 |
wcY1 = Math.abs(requestExtent.getMax().getY() - adjustedRequestExtent.getMax().getY());
|
|
284 |
initXPxBuf = (int)Math.floor((wcX1 * (sourceWithoutResampling.getWidth())) / requestExtent.width());
|
|
285 |
initYPxBuf = (int)Math.floor((wcY1 * (sourceWithoutResampling.getHeight())) / requestExtent.height());
|
270 |
286 |
|
271 |
287 |
//4-Copiar recorte al buffer
|
272 |
|
Rectangle2D rTile = new Rectangle2D.Double(points[0], points[2], (points[1] - points[0]) + 1, (points[3] - points[2]) + 1);
|
|
288 |
|
273 |
289 |
if(alpha)
|
274 |
290 |
loadBuffer(sourceWithoutResampling, transpList[i], rTile, initXPxBuf, initYPxBuf, true);
|
275 |
291 |
else
|
276 |
292 |
loadBuffer(sourceWithoutResampling, bufferList[i], rTile, initXPxBuf, initYPxBuf, false);
|
277 |
293 |
}
|
278 |
|
try {
|
279 |
|
save(sourceWithoutResampling, true, ext, null);
|
|
294 |
/*try {
|
|
295 |
save(sourceWithoutResampling, true, requestExtent, null);
|
280 |
296 |
} catch (NotSupportedExtensionException e) {
|
281 |
|
e.printStackTrace();
|
|
297 |
log.debug("Error saving in MemoryMatrixBuffer", e);
|
282 |
298 |
} catch (RasterDriverException e) {
|
283 |
|
e.printStackTrace();
|
|
299 |
log.debug("Error saving in MemoryMatrixBuffer", e);
|
284 |
300 |
} catch (ProcessInterruptedException e) {
|
285 |
|
e.printStackTrace();
|
|
301 |
log.debug("Error saving in MemoryMatrixBuffer", e);
|
286 |
302 |
} catch (IOException e) {
|
287 |
|
e.printStackTrace();
|
288 |
|
}
|
|
303 |
log.debug("Error saving in MemoryMatrixBuffer", e);
|
|
304 |
}*/
|
289 |
305 |
//Devuelve el buffer pero reescalandolo antes al tama?o en pixeles de la petici?n
|
290 |
306 |
try {
|
291 |
307 |
Buffer result = null;
|
... | ... | |
298 |
314 |
return buf;
|
299 |
315 |
}
|
300 |
316 |
|
301 |
|
private void save(Buffer bufResult,
|
302 |
|
boolean alphaBand,
|
303 |
|
Extent tileExtent,
|
304 |
|
ColorInterpretation colorInterpretation) throws NotSupportedExtensionException, RasterDriverException, ProcessInterruptedException, IOException {
|
305 |
|
//Escritura en disco del tile
|
306 |
|
RasterManager rManager = RasterLocator.getManager();
|
307 |
|
DataServerWriter dataWriter = RasterLocator.getManager().createDataServerWriter();
|
308 |
|
dataWriter.setBuffer(bufResult, -1);
|
309 |
|
Params params = rManager.createWriter("_.tif").getParams();
|
310 |
|
double pixelSize = (tileExtent.width() / bufResult.getWidth());
|
311 |
|
AffineTransform affineTransform = new AffineTransform(pixelSize, 0, 0, -pixelSize,
|
312 |
|
tileExtent.getULX(),
|
313 |
|
tileExtent.getULY());
|
314 |
|
RasterWriter rw = rManager.createWriter(dataWriter, "/tmp/prueba.tif",
|
315 |
|
bufResult.getBandCount(), affineTransform, bufResult.getWidth(),
|
316 |
|
bufResult.getHeight(), bufResult.getDataType(), params, null);
|
317 |
|
|
318 |
|
if(colorInterpretation != null) {
|
319 |
|
String[] values = colorInterpretation.getValues();
|
320 |
|
if(alphaBand) {
|
321 |
|
String[] newValues = values;
|
322 |
|
boolean exists = false;
|
323 |
|
for (int i = 0; i < values.length; i++) {
|
324 |
|
if(values[i] != null && values[i].compareTo("Alpha") == 0)
|
325 |
|
exists = true;
|
326 |
|
}
|
327 |
|
if(!exists) {
|
328 |
|
newValues = new String[values.length + 1];
|
329 |
|
for (int i = 0; i < values.length; i++) {
|
330 |
|
newValues[i] = values[i];
|
331 |
|
}
|
332 |
|
newValues[newValues.length - 1] = "Alpha";
|
333 |
|
}
|
334 |
|
rw.setColorBandsInterpretation(newValues);
|
335 |
|
}
|
336 |
|
|
337 |
|
} else {
|
338 |
|
if(alphaBand) {
|
339 |
|
String[] ci = new String[bufResult.getBandCount()];
|
340 |
|
if(bufResult.getBandCount() == 4) {
|
341 |
|
ci[0] = "Red";
|
342 |
|
ci[1] = "Green";
|
343 |
|
ci[2] = "Blue";
|
344 |
|
ci[3] = "Alpha";
|
345 |
|
} else {
|
346 |
|
for (int i = 0; i < bufResult.getBandCount(); i++) {
|
347 |
|
ci[i] = "Gray";
|
348 |
|
}
|
349 |
|
}
|
350 |
|
rw.setColorBandsInterpretation(ci);
|
351 |
|
}
|
352 |
|
}
|
353 |
|
rw.dataWrite();
|
354 |
|
rw.writeClose();
|
355 |
|
}
|
356 |
|
|
357 |
317 |
/**
|
358 |
|
* Builds a buffer in the same resolution as the list of tiles. When the operation
|
359 |
|
* ends this buffer should be resampled.
|
360 |
|
* @return
|
361 |
|
*/
|
362 |
|
private Buffer createBufferWithoutResampling(Extent extOrigin,
|
363 |
|
Buffer bufOrigin,
|
364 |
|
Rectangle2D extTile,
|
365 |
|
Buffer bufTile) {
|
366 |
|
double psOrigin = extOrigin.width() / bufOrigin.getWidth();
|
367 |
|
double psTile = extTile.getWidth() / bufTile.getWidth();
|
368 |
|
double rel = psTile / psOrigin;
|
369 |
|
int w = (int)Math.round(bufOrigin.getWidth() / rel);
|
370 |
|
int h = (int)Math.round(bufOrigin.getHeight() / rel);
|
371 |
|
return DefaultRasterManager.getInstance().createBuffer(bufOrigin.getDataType(), w, h, bufOrigin.getBandCount(), true);
|
372 |
|
}
|
373 |
|
|
374 |
|
/**
|
375 |
318 |
* Gets the point list to clip the tile
|
376 |
|
* @param r Bounding box of the tile
|
|
319 |
* @param extTile Bounding box of the tile
|
377 |
320 |
* @param b Buffer of the tile
|
378 |
321 |
* @param extentRequest
|
379 |
322 |
* @return
|
380 |
323 |
*/
|
381 |
|
private int[] getClipPoints(Rectangle2D r, Buffer b, Extent extentRequest) {
|
382 |
|
double widthWCTile = r.getWidth();
|
|
324 |
private Rectangle2D getClipPoints(Rectangle2D extTile, Buffer b, Extent extentRequest) {
|
|
325 |
double widthWCTile = extTile.getWidth();
|
383 |
326 |
double widthPXTile = b.getWidth();
|
384 |
|
double heightWCTile = r.getHeight();
|
|
327 |
double heightWCTile = extTile.getHeight();
|
385 |
328 |
double heightPXTile = b.getHeight();
|
386 |
329 |
|
387 |
330 |
//1-Ajustar peti?n al extent del tile
|
388 |
|
Extent adjustedRequestExtent = getAdjustedExtent(r, extentRequest);
|
|
331 |
Extent adjustedRequestExtent = getAdjustedExtent(extTile, extentRequest);
|
389 |
332 |
|
390 |
333 |
//2-Obtener el punto inicial y final del recorte del tile en pixeles
|
391 |
|
double wcX1 = adjustedRequestExtent.getMin().getX() - r.getX();
|
392 |
|
double wcX2 = adjustedRequestExtent.getMax().getX() - r.getX();
|
393 |
|
double wcY1 = r.getY() - adjustedRequestExtent.getMax().getY();
|
394 |
|
double wcY2 = r.getY() - adjustedRequestExtent.getMin().getY();
|
395 |
|
int initXPxTile = (int)((wcX1 * widthPXTile) / widthWCTile);
|
396 |
|
int endXPxTile = (int)(((wcX2 * widthPXTile) / widthWCTile) - 1);
|
397 |
|
int initYPxTile = (int)((wcY1 * heightPXTile) / heightWCTile);
|
398 |
|
int endYPxTile = (int)(((wcY2 * heightPXTile) / heightWCTile) - 1);
|
399 |
|
return new int[]{initXPxTile,
|
400 |
|
endXPxTile >= widthPXTile ? endXPxTile - 1 : endXPxTile,
|
|
334 |
double wcX1 = adjustedRequestExtent.getMin().getX() - extTile.getX();
|
|
335 |
double wcX2 = adjustedRequestExtent.getMax().getX() - extTile.getX();
|
|
336 |
double wcY1 = extTile.getY() - adjustedRequestExtent.getMax().getY();
|
|
337 |
double wcY2 = extTile.getY() - adjustedRequestExtent.getMin().getY();
|
|
338 |
int initXPxTile = (int)Math.floor((wcX1 * widthPXTile) / widthWCTile);
|
|
339 |
int endXPxTile = (int)Math.ceil((wcX2 * widthPXTile) / widthWCTile);
|
|
340 |
int initYPxTile = (int)Math.floor((wcY1 * heightPXTile) / heightWCTile);
|
|
341 |
int endYPxTile = (int)Math.ceil((wcY2 * heightPXTile) / heightWCTile);
|
|
342 |
endXPxTile = endXPxTile >= widthPXTile ? (int)(widthPXTile - 1) : endXPxTile;
|
|
343 |
endYPxTile = endYPxTile >= heightPXTile ? (int)(heightPXTile - 1) : endYPxTile;
|
|
344 |
|
|
345 |
return new Rectangle2D.Double(initXPxTile,
|
401 |
346 |
initYPxTile,
|
402 |
|
endYPxTile >= heightPXTile ? endYPxTile - 1 : endYPxTile};
|
|
347 |
Math.abs((endXPxTile - initXPxTile) + 1),
|
|
348 |
Math.abs((endYPxTile - initYPxTile) + 1));
|
403 |
349 |
}
|
404 |
350 |
|
405 |
351 |
/**
|
406 |
|
* Adjust the request to the tile bounding box
|
407 |
|
* @param tileExtent
|
408 |
|
* @param extentRequest
|
409 |
|
* @return
|
410 |
|
*/
|
411 |
|
private Extent getAdjustedExtent(Rectangle2D tileExtent, Extent extentRequest) {
|
412 |
|
double x1 = Math.max(extentRequest.getMin().getX(), tileExtent.getX());
|
413 |
|
double y1 = Math.min(extentRequest.getMax().getY(), tileExtent.getY());
|
414 |
|
double x2 = Math.min(extentRequest.getMax().getX(), (tileExtent.getX() + tileExtent.getWidth()));
|
415 |
|
double y2 = Math.max(extentRequest.getMin().getY(), (tileExtent.getY() - tileExtent.getHeight()));
|
416 |
|
return new ExtentImpl(x1, y1, x2, y2);
|
417 |
|
}
|
418 |
|
|
419 |
|
/**
|
420 |
352 |
* Write data in the source buffer taking into account the view shift
|
421 |
353 |
* @param sourceBuf
|
422 |
354 |
* @param tileBuf
|
... | ... | |
508 |
440 |
}
|
509 |
441 |
}
|
510 |
442 |
|
|
443 |
private void save(Buffer bufResult,
|
|
444 |
boolean alphaBand,
|
|
445 |
Extent tileExtent,
|
|
446 |
ColorInterpretation colorInterpretation) throws NotSupportedExtensionException, RasterDriverException, ProcessInterruptedException, IOException {
|
|
447 |
//Escritura en disco del tile
|
|
448 |
RasterManager rManager = RasterLocator.getManager();
|
|
449 |
DataServerWriter dataWriter = RasterLocator.getManager().createDataServerWriter();
|
|
450 |
dataWriter.setBuffer(bufResult, -1);
|
|
451 |
Params params = rManager.createWriter("_.tif").getParams();
|
|
452 |
double pixelSize = (tileExtent.width() / bufResult.getWidth());
|
|
453 |
AffineTransform affineTransform = new AffineTransform(pixelSize, 0, 0, -pixelSize,
|
|
454 |
tileExtent.getULX(),
|
|
455 |
tileExtent.getULY());
|
|
456 |
RasterWriter rw = rManager.createWriter(dataWriter, "/tmp/prueba.tif",
|
|
457 |
bufResult.getBandCount(), affineTransform, bufResult.getWidth(),
|
|
458 |
bufResult.getHeight(), bufResult.getDataType(), params, null);
|
|
459 |
|
|
460 |
if(colorInterpretation != null) {
|
|
461 |
String[] values = colorInterpretation.getValues();
|
|
462 |
if(alphaBand) {
|
|
463 |
String[] newValues = values;
|
|
464 |
boolean exists = false;
|
|
465 |
for (int i = 0; i < values.length; i++) {
|
|
466 |
if(values[i] != null && values[i].compareTo("Alpha") == 0)
|
|
467 |
exists = true;
|
|
468 |
}
|
|
469 |
if(!exists) {
|
|
470 |
newValues = new String[values.length + 1];
|
|
471 |
for (int i = 0; i < values.length; i++) {
|
|
472 |
newValues[i] = values[i];
|
|
473 |
}
|
|
474 |
newValues[newValues.length - 1] = "Alpha";
|
|
475 |
}
|
|
476 |
rw.setColorBandsInterpretation(newValues);
|
|
477 |
}
|
|
478 |
|
|
479 |
} else {
|
|
480 |
if(alphaBand) {
|
|
481 |
String[] ci = new String[bufResult.getBandCount()];
|
|
482 |
if(bufResult.getBandCount() == 4) {
|
|
483 |
ci[0] = "Red";
|
|
484 |
ci[1] = "Green";
|
|
485 |
ci[2] = "Blue";
|
|
486 |
ci[3] = "Alpha";
|
|
487 |
} else {
|
|
488 |
for (int i = 0; i < bufResult.getBandCount(); i++) {
|
|
489 |
ci[i] = "Gray";
|
|
490 |
}
|
|
491 |
}
|
|
492 |
rw.setColorBandsInterpretation(ci);
|
|
493 |
}
|
|
494 |
}
|
|
495 |
rw.dataWrite();
|
|
496 |
rw.writeClose();
|
|
497 |
}
|
|
498 |
|
|
499 |
/**
|
|
500 |
* Builds a buffer in the same resolution as the list of tiles. When the operation
|
|
501 |
* ends this buffer should be resampled.
|
|
502 |
* @return
|
|
503 |
*/
|
|
504 |
private Buffer createBufferWithoutResampling(Extent extOrigin,
|
|
505 |
Buffer bufOrigin,
|
|
506 |
Rectangle2D extTile,
|
|
507 |
Buffer bufTile) {
|
|
508 |
double psOrigin = extOrigin.width() / bufOrigin.getWidth();
|
|
509 |
double psTile = extTile.getWidth() / bufTile.getWidth();
|
|
510 |
double rel = psTile / psOrigin;
|
|
511 |
int w = (int)Math.floor(bufOrigin.getWidth() / rel);
|
|
512 |
int h = (int)Math.floor(bufOrigin.getHeight() / rel);
|
|
513 |
return DefaultRasterManager.getInstance().createBuffer(bufOrigin.getDataType(), w, h, bufOrigin.getBandCount(), true);
|
|
514 |
}
|
|
515 |
|
|
516 |
|
|
517 |
/**
|
|
518 |
* Adjust the request to the tile bounding box
|
|
519 |
* @param tileExtent
|
|
520 |
* @param extentRequest
|
|
521 |
* @return
|
|
522 |
*/
|
|
523 |
private Extent getAdjustedExtent(Rectangle2D tileExtent, Extent extentRequest) {
|
|
524 |
double x1 = Math.max(extentRequest.getMin().getX(), tileExtent.getX());
|
|
525 |
double y1 = Math.min(extentRequest.getMax().getY(), tileExtent.getY());
|
|
526 |
double x2 = Math.min(extentRequest.getMax().getX(), (tileExtent.getX() + tileExtent.getWidth()));
|
|
527 |
double y2 = Math.max(extentRequest.getMin().getY(), (tileExtent.getY() - tileExtent.getHeight()));
|
|
528 |
return new ExtentImpl(x1, y1, x2, y2);
|
|
529 |
}
|
|
530 |
|
511 |
531 |
|
512 |
532 |
/*private double clip(double value) {
|
513 |
533 |
return math.clipDecimals(value, 5);
|