Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.library / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.buffer.impl / src / main / java / org / gvsig / raster / lib / buffer / impl / BufferInterpolation.java @ 43867

History | View | Annotate | Download (28.2 KB)

1
package org.gvsig.raster.lib.buffer.impl;
2

    
3
import org.gvsig.raster.lib.buffer.api.Band;
4
import org.gvsig.raster.lib.buffer.api.Band.BandByte;
5
import org.gvsig.raster.lib.buffer.api.Band.BandDouble;
6
import org.gvsig.raster.lib.buffer.api.Band.BandFloat;
7
import org.gvsig.raster.lib.buffer.api.Band.BandInt;
8
import org.gvsig.raster.lib.buffer.api.Band.BandShort;
9
import org.gvsig.raster.lib.buffer.api.Buffer;
10
import org.gvsig.raster.lib.buffer.api.BufferManager;
11
import org.gvsig.tools.ToolsLocator;
12
import org.gvsig.tools.task.SimpleTaskStatus;
13

    
14
import org.slf4j.Logger;
15
import org.slf4j.LoggerFactory;
16

    
17
/**
18
 * @author fdiaz
19
 *
20
 */
21
public class BufferInterpolation {
22

    
23
    private static final Logger LOG = LoggerFactory.getLogger(BufferInterpolation.class);
24

    
25
    /**
26
     * @param buf
27
     */
28
    public BufferInterpolation() {
29
    }
30

    
31
    /**
32
     * Interpolates the buffer "source" to a number of columns and a number of rows
33
     * and stores the result in the buffer "targer" according to the nearest interpolation method.
34
     *
35
     * @param source
36
     * @param rows
37
     * @param columns
38
     * @param target
39
     * @param status
40
     */
41
    public void nearestNeighbourInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) {
42
        boolean isMyStatus = false;
43
        if (status == null) {
44
            status =
45
                ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Nearest neighbour interpolation");
46
            status.add();
47
            isMyStatus = true;
48
        } else {
49
            status.push();
50
        }
51
        try {
52
            int rows = target.getRows();
53
            int columns = target.getColumns();
54

    
55
            double stepX = (double) columns / (double) source.getColumns();
56
            double stepY = (double) rows / (double) source.getRows();
57

    
58
            status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
59
            status.message("Calculating interpolation");
60
            int count = 0;
61

    
62
            for (int iBand = 0; iBand < source.getBandCount(); iBand++) {
63
                Band sourceBand = source.getBand(iBand);
64
                Band targetBand = target.getBand(iBand);
65
                if (stepY < 1) {// submuestreo Y
66
                    int previousTargetRow = -1;
67
                    for (int sourceRow = 0; sourceRow < source.getRows(); sourceRow++) {
68
                        int targetRow = (int) (sourceRow * stepY);
69
                        if (targetRow != previousTargetRow) {
70
                            if (stepX < 1) { // submuestreo X
71
                                submuestreoX(source, stepX, sourceBand, targetBand, sourceRow, targetRow);
72
                            } else {
73
                                supermuestreoX(columns, stepX, sourceBand, targetBand, sourceRow, targetRow);
74
                            }
75
                            status.setCurValue(count+=source.getColumns());
76
                            if (status.isCancelled()) {
77
                                status.abort();
78
                                return;
79
                            }
80
                            previousTargetRow = targetRow;
81
                        } else {
82
                            count += source.getColumns();
83
                            status.setCurValue(count);
84
                        }
85
                    }
86
                } else { // supermuestreo Y
87
                    for (int targetRow = 0; targetRow < rows; targetRow++) {
88
                        int sourceRow = (int) (targetRow / stepY);
89
                        if (stepX < 1) { // submuestreo X
90
                            submuestreoX(source, stepX, sourceBand, targetBand, sourceRow, targetRow);
91
                        } else {
92
                            supermuestreoX(columns, stepX, sourceBand, targetBand, sourceRow, targetRow);
93
                        }
94
                        status.setCurValue(count+=source.getColumns());
95
                        if (status.isCancelled()) {
96
                            status.abort();
97
                            return;
98
                        }
99
                    }
100
                }
101
            }
102

    
103
            if (isMyStatus) {
104
                status.terminate();
105
            } else {
106
                status.pop();
107
            }
108
        } catch (Exception e) {
109
            status.abort();
110
            throw e;
111
        }
112
        return;
113

    
114
    }
115

    
116
    /**
117
     * @param columns
118
     * @param stepX
119
     * @param sourceBand
120
     * @param targetBand
121
     * @param sourceRow
122
     * @param targetRow
123
     */
124
    private void supermuestreoX(int columns, double stepX, Band sourceBand, Band targetBand, int sourceRow,
125
        int targetRow) {
126
        for (int targetCol = 0; targetCol < columns; targetCol++) {
127
            int sourceColumn = (int) (targetCol / stepX);
128
            targetBand.set(targetRow, targetCol, sourceBand.get(sourceRow, sourceColumn));
129
        }
130
    }
131

    
132
    /**
133
     * @param source
134
     * @param stepX
135
     * @param sourceBand
136
     * @param targetBand
137
     * @param sourceRow
138
     * @param targetRow
139
     */
140
    private void submuestreoX(Buffer source, double stepX, Band sourceBand, Band targetBand, int sourceRow, int targetRow) {
141
        int previousTargetColumn = -1;
142
        for (int sourceCol = 0; sourceCol < source.getColumns(); sourceCol++) {
143
            int targetColumn = (int) (sourceCol * stepX);
144
            if (targetColumn != previousTargetColumn) {
145
                Object value = sourceBand.get(sourceRow, sourceCol);
146
                targetBand.set(targetRow, targetColumn, value);
147
                previousTargetColumn = targetColumn;
148
            }
149
        }
150
    }
151

    
152
    /**
153
     * Interpolates the buffer "source" to a number of columns and a number of rows
154
     * and stores the result in the buffer "targer" according to the bilinear interpolation method.
155
     *
156
     * Promedia el valor de cuatro pixeles adyacentes.
157
     * <P>
158
     * Para cada pixel del raster A:(x, y) obtiene el B:(x + 1, y), C:(x, y +
159
     * 1), D:(x + 1, y + 1) Para cada valor del kernel se calcula un valor 'd'
160
     * que es un peso dependiendo de su posici?n. Este peso depende de la
161
     * posici?n del pixel destino dentro del origen. La posici?n del pixel
162
     * destino en el origen es un valor decimal que puede ir de 0 a 1. Si est?
163
     * muy pegado a la esquina superior izquierda estar? cercano a 0 y si est?
164
     * muy pegado a la esquina inferior derecha estar? cercano a 1. Este valor
165
     * est? representado por 'dx' y 'dy'.
166
     * </P>
167
     * <P>
168
     * Los pesos aplicados son a
169
     * <UL>
170
     * <LI>A (1-dx) * (1-dy)</LI>
171
     * <LI>B dx * (1-dy)</LI>
172
     * <LI>C (1-dx) * dy</LI>
173
     * <LI>D dx * dy</LI>
174
     * </UL>
175
     * La variable 'z' contiene el valor acumulado de cada peso por el valor del
176
     * pixel. La variable 'n' contiene el valor acumulado de los pesos de los
177
     * cuatro pixeles. El valor final del pixel ser? 'z/n', es decir un promedio
178
     * del valor de los cuatro teniendo en cuenta el peso de cada uno.
179
     * </P>
180
     * @param source
181
     * @param rows
182
     * @param columns
183
     * @param target
184
     * @param status
185
     *
186
     */
187
    public void bilinearInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) {
188

    
189
        boolean isMyStatus = false;
190
        if (status == null) {
191
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Bilinear interpolation");
192
            status.add();
193
            isMyStatus = true;
194
        } else {
195
            status.push();
196
        }
197
        status.add();
198
        try {
199
            int rows = target.getRows();
200
            int columns = target.getColumns();
201

    
202
            double pxSizeX = (double) source.getColumns() / (double) columns;
203
            double pxSizeY = (double) source.getRows() / (double) rows;
204

    
205
            double posX, posY;
206
            double dx = 0D, dy = 0D;
207
            int bandCount = source.getBandCount();
208
            for (int iBand = 0; iBand < bandCount; iBand++) {
209
                status.setRangeOfValues(0, source.getRows());
210
                status.message("Interpolating, band "+iBand+"/"+ bandCount);
211
                status.setCurValue(0);
212
                posY = pxSizeY / 2D;
213
                Band sourceBand = source.getBand(iBand);
214
                Band targetBand = target.getBand(iBand);
215
                for (int iRow = 0; iRow < rows; iRow++) {
216
                    status.setCurValue(iRow);
217
                    if (status.isCancelled()) {
218
                        status.abort();
219
                        return;
220
                    }
221
                    dy = posY - ((int) posY);
222
                    posX = pxSizeX / 2D;
223
                    for (int iCol = 0; iCol < columns; iCol++) {
224
                        dx = posX - ((int) posX);
225
                        try {
226
                            double[] kernel = getKernel((int) posY, (int) posX, sourceBand);
227
                            setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel));
228
                        } catch (ArrayIndexOutOfBoundsException e) {
229
                            LOG.warn(
230
                                "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
231
                                new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow,
232
                                    iCol, dx, dy});
233
                        }
234
                        posX += pxSizeX;
235
                    }
236
                    posY += pxSizeY;
237
                }
238
            }
239

    
240
            if (isMyStatus) {
241
                status.terminate();
242
            } else {
243
                status.pop();
244
            }
245
        } catch (Exception e) {
246
            status.abort();
247
            throw e;
248
        }
249
    }
250

    
251
    /**
252
     * Interpolates the buffer "source" to a number of columns and a number of rows
253
     * and stores the result in the buffer "targer" according to the inverse distance interpolation method.
254
     *
255
     * Asigna el valor de un pixel en funci?n inversa de la distancia.
256
     * <P>
257
     * Para cada pixel del raster A:(x, y) obtiene el B:(x + 1, y), C:(x, y +
258
     * 1), D:(x + 1, y + 1) Para cada valor del kernel se calcula un valor 'd'
259
     * que es un peso dependiendo de su posici?n. Este peso ser? dependiente de
260
     * la posici?n del pixel destino dentro del origen. La posici?n del pixel
261
     * destino en el origen es un valor decimal que puede ir de 0 a 1. Si est?
262
     * muy pegado a la esquina superior izquierda estar? cercano a 0 y si est?
263
     * muy pegado a la esquina inferior derecha estar? cercano a 1. Este valor
264
     * est? representado por 'dx' y 'dy'. En este caso, y a diferencia del
265
     * m?todo bilinear el peso vendr? representado por la inversa de la
266
     * distancia entre la posici?n dentro del pixel y el origen del mismo.
267
     * </P>
268
     * <P>
269
     * Los pesos aplicados son a
270
     * <UL>
271
     * <LI>A 1 / sqrt((1-dx) * (1-dy))</LI>
272
     * <LI>B 1 / sqrt(dx * (1-dy))</LI>
273
     * <LI>C 1 / sqrt((1-dx) * dy)</LI>
274
     * <LI>D 1 / sqrt(dx * dy)</LI>
275
     * </UL>
276
     * La variable 'z' contiene el valor acumulado de cada peso por el valor del
277
     * pixel. La variable 'n' contiene el valor acumulado de los pesos de los
278
     * cuatro pixeles. El valor final del pixel ser? 'z/n', es decir un promedio
279
     * del valor de los cuatro teniendo en cuenta el peso de cada uno.
280
     * </P>
281
     * @param source
282
     * @param rows
283
     * @param columns
284
     * @param target
285
     * @param status
286
     */
287
    public void inverseDistanceInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) {
288

    
289
        boolean isMyStatus = false;
290
        if (status == null) {
291
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Inverse distance interpolation");
292
            status.add();
293
            isMyStatus = true;
294
        } else {
295
            status.push();
296
        }
297
        try {
298
            int rows = target.getRows();
299
            int columns = target.getColumns();
300

    
301
            double pxSizeX = (double) source.getColumns() / (double) columns;
302
            double pxSizeY = (double) source.getRows() / (double) rows;
303

    
304
            status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
305
            status.message("Calculating interpolation");
306
            int count = 0;
307
            double posX, posY;
308
            double dx = 0D, dy = 0D;
309

    
310
            for (int iBand = 0; iBand < source.getBandCount(); iBand++) {
311
                posY = pxSizeY / 2D;
312
                Band sourceBand = source.getBand(iBand);
313
                Band targetBand = target.getBand(iBand);
314
                for (int iRow = 0; iRow < rows; iRow++) {
315
                    dy = posY - ((int) posY);
316
                    posX = pxSizeX / 2D;
317
                    for (int iCol = 0; iCol < columns; iCol++) {
318
                        status.setCurValue(count++);
319
                        if (status.isCancelled()) {
320
                            status.abort();
321
                            return;
322
                        }
323
                        dx = posX - ((int) posX);
324
                        try {
325
                            double[] kernel = getKernel(((int) posY), ((int) posX), sourceBand);
326
                            setBandValueFromDouble(iRow, iCol, targetBand, getInverseDistanceValue(dx, dy, kernel));
327
                        } catch (ArrayIndexOutOfBoundsException e) {
328
                            LOG.warn(
329
                                "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
330
                                new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow,
331
                                    iCol, dx, dy});
332
                        }
333
                        posX += pxSizeX;
334
                    }
335
                    posY += pxSizeY;
336
                }
337
            }
338

    
339
            if (isMyStatus) {
340
                status.terminate();
341
            } else {
342
                status.pop();
343
            }
344
        } catch (Exception e) {
345
            status.abort();
346
            throw e;
347
        }
348
        return;
349
    }
350

    
351
    /**
352
     * Interpolates the buffer "source" to a number of columns and a number of rows
353
     * and stores the result in the buffer "targer" according to the bicubic spline interpolation method.
354
     * el valor de cuatro pixeles adyacentes.
355
     * @param source
356
     * @param rows
357
     * @param columns
358
     * @param target
359
     * @param status
360
     */
361
    public void bicubicSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) {
362
        boolean isMyStatus = false;
363
        if (status == null) {
364
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Bicubic spline interpolation");
365
            status.add();
366
            isMyStatus = true;
367
        } else {
368
            status.push();
369
        }
370
        try {
371
            int rows = target.getRows();
372
            int columns = target.getColumns();
373

    
374
            double pxSizeX = (double) source.getColumns() / (double) columns;
375
            double pxSizeY = (double) source.getRows() / (double) rows;
376

    
377
            status.setRangeOfValues(0, source.getRows()*source.getBandCount());
378
            status.message("Calculating interpolation");
379
            int count = 0;
380
            double posX, posY;
381
            double dx = 0D, dy = 0D;
382

    
383
            for (int iBand = 0; iBand < source.getBandCount(); iBand++) {
384
                posY = pxSizeY / 2D;
385
                Band sourceBand = source.getBand(iBand);
386
                Band targetBand = target.getBand(iBand);
387
                for (int iRow = 0; iRow < rows; iRow++) {
388
                    status.setCurValue(count++);
389
                    if (status.isCancelled()) {
390
                        status.abort();
391
                        return;
392
                    }
393
                    dy = posY - ((int) posY);
394
                    posX = pxSizeX / 2D;
395
                    for (int iCol = 0; iCol < columns; iCol++) {
396
                        dx = posX - ((int) posX);
397
                        try {
398
                            double[][] submatrix = get4x4Submatrix(((int) posY), ((int) posX), source, sourceBand);
399
                            if (submatrix == null) {
400
                                double[] kernel = getKernel((int) posY, (int) posX, sourceBand);
401
                                setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel));
402
                            } else {
403
                                setBandValueFromDouble(iRow, iCol, targetBand, getBSplineValue(dx, dy, submatrix));
404
                            }
405
                        } catch (ArrayIndexOutOfBoundsException e) {
406
                            LOG.warn(
407
                                "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
408
                                new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow,
409
                                    iCol, dx, dy});
410
                        }
411
                        posX += pxSizeX;
412
                    }
413
                    posY += pxSizeY;
414
                }
415
            }
416

    
417
            if (isMyStatus) {
418
                status.terminate();
419
            } else {
420
                status.pop();
421
            }
422
        } catch (Exception e) {
423
            status.abort();
424
            throw e;
425
        }
426
        return;
427
    }
428

    
429
    /**
430
     * Interpolates the buffer "source" to a number of columns and a number of rows
431
     * and stores the result in the buffer "targer" according to the bSplineInterpolation method.
432
     * @param source
433
     * @param rows
434
     * @param columns
435
     * @param target
436
     * @param status
437
     */
438
    public void bSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) {
439

    
440
        boolean isMyStatus = false;
441
        if (status == null) {
442
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("BSpline interpolation");
443
            status.add();
444
            isMyStatus = true;
445
        } else {
446
            status.push();
447
        }
448
        try {
449
            int rows = target.getRows();
450
            int columns = target.getColumns();
451

    
452
            double pxSizeX = (double) source.getColumns() / (double) columns;
453
            double pxSizeY = (double) source.getRows() / (double) rows;
454

    
455
            status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
456
            status.message("Calculating interpolation");
457
            int count = 0;
458
            double posX, posY;
459
            double dx = 0D, dy = 0D;
460

    
461
            for (int iBand = 0; iBand < source.getBandCount(); iBand++) {
462
                posY = pxSizeY / 2D;
463
                Band sourceBand = source.getBand(iBand);
464
                Band targetBand = target.getBand(iBand);
465
                for (int iRow = 0; iRow < rows; iRow++) {
466
                    dy = posY - ((int) posY);
467
                    posX = pxSizeX / 2D;
468
                    for (int iCol = 0; iCol < columns; iCol++) {
469
                        status.setCurValue(count++);
470
                        if (status.isCancelled()) {
471
                            status.abort();
472
                            return;
473
                        }
474
                        dx = posX - ((int) posX);
475
                        try {
476
                            double[][] submatrix = get4x4Submatrix(((int) posY), ((int) posX), source, sourceBand);
477
                            if (submatrix == null) {
478
                                double[] kernel = getKernel( ((int) posY), ((int) posX),sourceBand);
479
                                setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel));
480
                            } else {
481
                                setBandValueFromDouble(iRow, iCol, targetBand, getBicubicSplineValue(dx, dy, submatrix));
482
                            }
483
                        } catch (ArrayIndexOutOfBoundsException e) {
484
                            LOG.warn(
485
                                "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
486
                                new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow,
487
                                    iCol, dx, dy });
488
                        }
489
                        posX += pxSizeX;
490
                    }
491
                    posY += pxSizeY;
492
                }
493
            }
494

    
495
            if (isMyStatus) {
496
                status.terminate();
497
            } else {
498
                status.pop();
499
            }
500
        } catch (Exception e) {
501
            status.abort();
502
            throw e;
503
        }
504
        return;
505
    }
506

    
507
    /**
508
     *
509
     * @param dx
510
     * @param dy
511
     * @param kernel
512
     * @return
513
     */
514
    private double getBicubicSplineValue(double dx, double dy, double[][] kernel) {
515
        int i;
516
        double a0, a2, a3, b1, b2, b3;
517
        double[] c = new double[4];
518

    
519
        for (i = 0; i < 4; i++) {
520
            a0 = kernel[0][i] - kernel[1][i];
521
            a2 = kernel[2][i] - kernel[1][i];
522
            a3 = kernel[3][i] - kernel[1][i];
523

    
524
            b1 = -a0 / 3.0 + a2 - a3 / 6.0;
525
            b2 = a0 / 2.0 + a2 / 2.0;
526
            b3 = -a0 / 6.0 - a2 / 2.0 + a3 / 6.0;
527

    
528
            c[i] = kernel[1][i] + b1 * dx + b2 * (dx * dx) + b3 * (dx * dx * dx);
529
        }
530

    
531
        a0 = c[0] - c[1];
532
        a2 = c[2] - c[1];
533
        a3 = c[3] - c[1];
534

    
535
        b1 = -a0 / 3.0 + a2 - a3 / 6.0;
536
        b2 = a0 / 2.0 + a2 / 2.0;
537
        b3 = -a0 / 6.0 - a2 / 2.0 + a3 / 6.0;
538

    
539
        return (c[1] + b1 * dy + b2 * (dy * dy) + b3 * (dy * dy * dy));
540
    }
541

    
542
    /**
543
     *
544
     * @param dx
545
     * @param dy
546
     * @param kernel
547
     * @return
548
     */
549
    private double getBSplineValue(double dx, double dy, double[][] kernel) {
550
        int i = 0, ix = 0, iy = 0;
551
        double px = 0, py = 0, z = 0;
552
        double[] Rx = new double[4];
553
        double[] Ry = new double[4];
554

    
555
        for (i = 0, px = -1.0 - dx, py = -1.0 - dy; i < 4; i++, px++, py++) {
556
            Rx[i] = 0.0;
557
            Ry[i] = 0.0;
558

    
559
            if ((z = px + 2.0) > 0.0)
560
                Rx[i] += z * z * z;
561
            if ((z = px + 1.0) > 0.0)
562
                Rx[i] += -4.0 * z * z * z;
563
            if ((z = px + 0.0) > 0.0)
564
                Rx[i] += 6.0 * z * z * z;
565
            if ((z = px - 1.0) > 0.0)
566
                Rx[i] += -4.0 * z * z * z;
567
            if ((z = py + 2.0) > 0.0)
568
                Ry[i] += z * z * z;
569
            if ((z = py + 1.0) > 0.0)
570
                Ry[i] += -4.0 * z * z * z;
571
            if ((z = py + 0.0) > 0.0)
572
                Ry[i] += 6.0 * z * z * z;
573
            if ((z = py - 1.0) > 0.0)
574
                Ry[i] += -4.0 * z * z * z;
575

    
576
            Rx[i] /= 6.0;
577
            Ry[i] /= 6.0;
578
        }
579

    
580
        for (iy = 0, z = 0.0; iy < 4; iy++) {
581
            for (ix = 0; ix < 4; ix++) {
582
                z += kernel[ix][iy] * Rx[ix] * Ry[iy];
583
            }
584
        }
585
        return z;
586
    }
587

    
588
    /**
589
     * Calcula los valores N y Z para el m?todo bilinear y obtiene el valor del
590
     * pixel como
591
     * Z / N
592
     *
593
     * @param dx
594
     *            distancia en X desde el centro del pixel hasta el punto. Es un
595
     *            valor entre 0 y 1
596
     * @param dy
597
     *            distancia en Y desde el centro del pixel hasta el punto. Es un
598
     *            valor entre 0 y 1
599
     * @param kernel
600
     *            valor del pixel y alrededor
601
     * @return valor del pixel
602
     */
603
    private double getBilinearValue(double dx, double dy, double[] kernel) {
604
        double z = 0.0, n = 0.0, d;
605
        d = (1.0 - dx) * (1.0 - dy);
606
        z += d * kernel[0];
607
        n += d;
608

    
609
        d = dx * (1.0 - dy);
610
        z += d * kernel[1];
611
        n += d;
612

    
613
        d = (1.0 - dx) * dy;
614
        z += d * kernel[2];
615
        n += d;
616

    
617
        d = dx * dy;
618
        z += d * kernel[3];
619
        n += d;
620

    
621
        double b = 0;
622
        if (n > 0.0) {
623
            b = (z / n);
624
        }
625
        return b;
626
    }
627

    
628
    /**
629
     * Calcula los valores N y Z para el m?todo de distancia inversa y calcula
630
     * el valor del
631
     * pixel como Z / N.
632
     *
633
     * @param dx
634
     *            distancia en X desde el centro del pixel hasta el punto. Es un
635
     *            valor entre 0 y 1
636
     * @param dy
637
     *            distancia en Y desde el centro del pixel hasta el punto. Es un
638
     *            valor entre 0 y 1
639
     * @param kernel
640
     *            valor del pixel y alrededor
641
     * @return valor del pixel
642
     */
643
    private double getInverseDistanceValue(double dx, double dy, double[] kernel) {
644
        double z = 0.0, n = 0.0, d;
645
        double t = Math.sqrt(dx * dx + dy * dy);
646
        d = 1.0 / ((t == 0) ? 0.5 : t);
647
        z += d * kernel[0];
648
        n += d;
649

    
650
        t = Math.sqrt((1.0 - dx) * (1.0 - dx) + dy * dy);
651
        d = 1.0 / ((t == 0) ? 0.5 : t);
652
        z += d * kernel[1];
653
        n += d;
654

    
655
        t = Math.sqrt(dx * dx + (1.0 - dy) * (1.0 - dy));
656
        d = 1.0 / ((t == 0) ? 0.5 : t);
657
        z += d * kernel[2];
658
        n += d;
659

    
660
        t = Math.sqrt((1.0 - dx) * (1.0 - dx) + (1.0 - dy) * (1.0 - dy));
661
        d = 1.0 / ((t == 0) ? 0.5 : t);
662
        z += d * kernel[3];
663
        n += d;
664

    
665
        double b = 0;
666
        if (n > 0.0) {
667
            b = (z / n);
668
        }
669
        return b;
670
    }
671

    
672
    /**
673
     * Obtiene un kernel de 4x4 elementos. Si alguno de los elementos se sale de
674
     * la imagen
675
     * , por ejemplo en los bordes devuelve null.
676
     *
677
     * @param column
678
     * @param row
679
     * @param band
680
     * @return
681
     */
682
    private double[][] get4x4Submatrix( int row, int column, Buffer buffer, Band band) {
683
        int ix, iy, px, py;
684
        double[][] z_xy = new double[4][4];
685

    
686
        for (iy = 0, py = row - 1; iy < 4; iy++, py++) {
687
            for (ix = 0, px = column - 1; ix < 4; ix++, px++) {
688
                if (!buffer.isInside(px, py)) {
689
                    return null;
690
                } else {
691
                    z_xy[ix][iy] = getBandValueToDouble(py, px, band);
692
                }
693
            }
694
        }
695
        return z_xy;
696
    }
697

    
698
    /**
699
     * Obtiene un kernel de cuatro elemento que corresponden a los pixeles (x,
700
     * y), (x + 1, y),
701
     * (x, y + 1), (x + 1, y + 1). Si los pixeles x + 1 o y + 1 se salen del
702
     * raster de origen
703
     * se tomar? x e y.
704
     *
705
     * @param x
706
     *            Coordenada X del pixel inicial
707
     * @param y
708
     *            Coordenada Y del pixel inicial
709
     * @param band
710
     *            the band
711
     * @return Kernel solicitado en forma de array.
712
     */
713
    private double[] getKernel(int row, int column, Band band) {
714
        double[] d = new double[4];
715
        d[0] = getBandValueToDouble(row, column, band);
716
        int nextColumn = ((column + 1) >= band.getColumns()) ? column : (column + 1);
717
        int nextRow = ((row + 1) >= band.getRows()) ? row : (row + 1);
718
        d[1] = getBandValueToDouble(row, nextColumn, band);
719
        d[2] = getBandValueToDouble(nextRow, column, band);
720
        d[3] = getBandValueToDouble(nextRow, nextColumn, band);
721
        return d;
722
    }
723

    
724
    private double getBandValueToDouble(int row, int column, Band band) {
725
        switch (band.getDataType()) {
726
        case BufferManager.TYPE_BYTE:
727
            return ((BandByte) band).getValue(row, column) & 0xff;
728
        case BufferManager.TYPE_SHORT:
729
        case BufferManager.TYPE_USHORT:
730
            return ((BandShort) band).getValue(row, column) & 0xffff;
731
        case BufferManager.TYPE_INT:
732
            return ((BandInt) band).getValue(row, column) & 0xffffffff;
733
        case BufferManager.TYPE_FLOAT:
734
            return ((BandFloat) band).getValue(row, column);
735
        case BufferManager.TYPE_DOUBLE:
736
            return ((BandDouble) band).getValue(row, column);
737
        default:
738
            throw new IllegalArgumentException("Unknow dataType " + band.getDataType() + ".");
739
        }
740
    }
741

    
742
    private void setBandValueFromDouble(int row, int column, Band band, Number value) {
743
        switch (band.getDataType()) {
744
        case BufferManager.TYPE_BYTE:
745
            ((BandByte) band).setValue(row, column, value.byteValue());
746
            break;
747
        case BufferManager.TYPE_SHORT:
748
        case BufferManager.TYPE_USHORT:
749
            ((BandShort) band).setValue(row, column, value.shortValue());
750
            break;
751
        case BufferManager.TYPE_INT:
752
            ((BandInt) band).setValue(row, column, value.intValue());
753
            break;
754
        case BufferManager.TYPE_FLOAT:
755
            ((BandFloat) band).setValue(row, column, value.floatValue());
756
            break;
757
        case BufferManager.TYPE_DOUBLE:
758
            ((BandDouble) band).setValue(row, column, value.doubleValue());
759
            break;
760
        default:
761
            throw new IllegalArgumentException("Unknow dataType " + band.getDataType() + ".");
762
        }
763
    }
764
}