PageRenderTime 69ms CodeModel.GetById 14ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

/alaspatial/src/main/java/org/ala/spatial/util/GridCutter.java

http://alageospatialportal.googlecode.com/
Java | 717 lines | 510 code | 84 blank | 123 comment | 133 complexity | b69198513c8d42ded6a159cd5f32bfdd MD5 | raw file
  1/**
  2 * ************************************************************************
  3 * Copyright (C) 2010 Atlas of Living Australia All Rights Reserved.
  4 *
  5 * The contents of this file are subject to the Mozilla Public License Version
  6 * 1.1 (the "License"); you may not use this file except in compliance with the
  7 * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
  8 *
  9 * Software distributed under the License is distributed on an "AS IS" basis,
 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 11 * the specific language governing rights and limitations under the License.
 12 * *************************************************************************
 13 */
 14package org.ala.spatial.util;
 15
 16import java.io.File;
 17import java.io.FileWriter;
 18import java.util.ArrayList;
 19import java.util.TreeMap;
 20import org.ala.layers.client.Client;
 21import org.ala.layers.intersect.Grid;
 22import org.ala.layers.intersect.SimpleRegion;
 23import org.ala.layers.util.SpatialUtil;
 24import org.ala.spatial.analysis.index.LayerFilter;
 25
 26/**
 27 * Class for region cutting test data grids
 28 *
 29 * @author adam
 30 */
 31public class GridCutter {
 32
 33    public static ArrayList<Object> loadCutGridsForAloc(File[] files, String extentsFilename, int pieces, AnalysisJob job) {
 34        ArrayList<Object> data = new ArrayList<Object>();
 35
 36        if (job != null) {
 37            job.setProgress(0);
 38        }
 39
 40        //determine outer bounds of layers
 41        double xmin = Double.MAX_VALUE;
 42        double ymin = Double.MAX_VALUE;
 43        double xmax = Double.MAX_VALUE * -1;
 44        double ymax = Double.MAX_VALUE * -1;
 45        double xres = 0.01;
 46        double yres = 0.01;
 47        for (File f : files) {
 48            String gridFilename = f.getPath().substring(0, f.getPath().length() - 4);
 49            Grid g = new Grid(gridFilename);
 50            xres = g.xres;
 51            yres = g.xres;
 52            if (xmin > g.xmin) {
 53                xmin = g.xmin;
 54            }
 55            if (xmax < g.xmax) {
 56                xmax = g.xmax;
 57            }
 58            if (ymin > g.ymin) {
 59                ymin = g.ymin;
 60            }
 61            if (ymax < g.ymax) {
 62                ymax = g.ymax;
 63            }
 64        }
 65
 66        if (files.length < 2) {
 67            if (job != null) {
 68                job.setCurrentState(AnalysisJob.FAILED);
 69                job.log("Fewer than two layers with postive range.");
 70            } else {
 71                SpatialLogger.log("Fewer than two layers with postive range.");
 72            }
 73            return null;
 74        }
 75
 76
 77        //determine range and width's
 78        double xrange = xmax - xmin;
 79        double yrange = ymax - ymin;
 80        int width = (int) Math.ceil(xrange / xres);
 81        int height = (int) Math.ceil(yrange / yres);
 82
 83        //write extents into a file now
 84        if (extentsFilename != null) {
 85            try {
 86                FileWriter fw = new FileWriter(extentsFilename);
 87                fw.append(String.valueOf(width)).append("\n");
 88                fw.append(String.valueOf(height)).append("\n");
 89                fw.append(String.valueOf(xmin)).append("\n");
 90                fw.append(String.valueOf(ymin)).append("\n");
 91                fw.append(String.valueOf(xmax)).append("\n");
 92                fw.append(String.valueOf(ymax));
 93                fw.close();
 94            } catch (Exception e) {
 95                e.printStackTrace();
 96            }
 97        }
 98
 99        if (job != null) {
100            job.setProgress(0.1, "exported extents");
101        }
102
103        //make cells list for outer bounds
104        int th = height;
105        int tw = width;
106        int tp = 0;
107        int[][] cells = new int[tw * th][2];
108        for (int i = 0; i < height; i++) {
109            for (int j = 0; j < width; j++) {
110                cells[tp][0] = j;
111                cells[tp][1] = i;
112                tp++;
113            }
114        }
115
116        if (job != null) {
117            job.setProgress(0.2, "determined target cells");
118        }
119
120        if (job != null) {
121            job.log("Cut cells count: " + cells.length);
122        } else {
123            System.out.println("Cut cells count: " + cells.length);
124        }
125
126        //transform cells numbers to long/lat numbers
127        double[][] points = new double[cells.length][2];
128        for (int i = 0; i < cells.length; i++) {
129            points[i][0] = xmin + cells[i][0] * xres;
130            points[i][1] = ymin + cells[i][1] * yres;
131        }
132
133        //initialize data structure to hold everything
134        // each data piece: row1[col1, col2, ...] row2[col1, col2, ...] row3...
135        int remainingLength = cells.length;
136        int step = (int) Math.floor(remainingLength / (double) pieces);
137        for (int i = 0; i < pieces; i++) {
138            if (i == pieces - 1) {
139                data.add(new float[remainingLength * files.length]);
140            } else {
141                data.add(new float[step * files.length]);
142                remainingLength -= step;
143            }
144        }
145
146        //iterate for layers
147        double[] layerExtents = new double[files.length * 2];
148        for (int j = 0; j < files.length; j++) {
149            String gridFilename = files[j].getPath().substring(0, files[j].getPath().length() - 4);
150            Grid g = new Grid(gridFilename);
151            float[] v = g.getValues2(points);
152
153            //row range standardization
154            float minv = Float.MAX_VALUE;
155            float maxv = Float.MAX_VALUE * -1;
156            for (int i = 0; i < v.length; i++) {
157                if (v[i] < minv) {
158                    minv = v[i];
159                }
160                if (v[i] > maxv) {
161                    maxv = v[i];
162                }
163            }
164            float range = maxv - minv;
165            if (range > 0) {
166                for (int i = 0; i < v.length; i++) {
167                    v[i] = (v[i] - minv) / range;
168                }
169            } else {
170                for (int i = 0; i < v.length; i++) {
171                    v[i] = 0;
172                }
173            }
174            layerExtents[j * 2] = minv;
175            layerExtents[j * 2 + 1] = maxv;
176
177            //iterate for pieces
178            for (int i = 0; i < pieces; i++) {
179                float[] d = (float[]) data.get(i);
180                for (int k = j, n = i * step; k < d.length; k += files.length, n++) {
181                    d[k] = v[n];
182                }
183            }
184
185            if (job != null) {
186                job.setProgress(0.2 + j / (double) files.length * 7 / 10.0, "opened grid: " + files[j].getName());
187            }
188        }
189
190        if (job != null) {
191            job.log("finished opening grids");
192        }
193
194        //remove null rows from data and cells
195        int newCellPos = 0;
196        int currentCellPos = 0;
197        for (int i = 0; i < pieces; i++) {
198            float[] d = (float[]) data.get(i);
199            int newPos = 0;
200            for (int k = 0; k < d.length; k += files.length) {
201                int nMissing = 0;
202                for (int j = 0; j < files.length; j++) {
203                    if (Float.isNaN(d[k + j])) {
204                        nMissing++;
205                    }
206                }
207                //if (nMissing < files.length) {
208                if (nMissing == 0) {
209                    if (newPos < k) {
210                        for (int j = 0; j < files.length; j++) {
211                            d[newPos + j] = d[k + j];
212                        }
213                    }
214                    newPos += files.length;
215                    if (newCellPos < currentCellPos) {
216                        cells[newCellPos][0] = cells[currentCellPos][0];
217                        cells[newCellPos][1] = cells[currentCellPos][1];
218                    }
219                    newCellPos++;
220                }
221                currentCellPos++;
222            }
223            if (newPos < d.length) {
224                d = java.util.Arrays.copyOf(d, newPos);
225                data.set(i, d);
226            }
227        }
228
229        //remove zero length data pieces
230        for (int i = pieces - 1; i >= 0; i--) {
231            float[] d = (float[]) data.get(i);
232            if (d.length == 0) {
233                data.remove(i);
234            }
235        }
236
237        //add cells reference to output
238        data.add(cells);
239
240        //add extents to output
241        double[] extents = new double[6 + layerExtents.length];
242        extents[0] = width;
243        extents[1] = height;
244        extents[2] = xmin;
245        extents[3] = ymin;
246        extents[4] = xmax;
247        extents[5] = ymax;
248        for (int i = 0; i < layerExtents.length; i++) {
249            extents[6 + i] = layerExtents[i];
250        }
251        data.add(extents);
252
253        if (job != null) {
254            job.setProgress(1, "cleaned data");
255        }
256
257        return data;
258    }
259
260    /**
261     * exports a list of layers cut against a region
262     *
263     * Cut layer files generated are input layers with grid cells outside of
264     * region set as missing.
265     *
266     * @param layers list of layer fieldIds to be cut as String[].
267     * @param resolution target resolution as String
268     * @param region null or region to cut against as SimpleRegion. Cannot be
269     * used with envelopes.
270     * @param envelopes nul or region to cut against as LayerFilter[]. Cannot be
271     * used with region.
272     * @param extentsFilename output filename and path for writing output
273     * extents.
274     * @return directory containing the cut grid files.
275     */
276    public static String cut2(String[] layers, String resolution, SimpleRegion region, LayerFilter[] envelopes, String extentsFilename) {
277        //check if resolution needs changing
278        resolution = confirmResolution(layers, resolution);
279
280        //get extents for all layers
281        double[][] extents = getLayerExtents(resolution, layers[0]);
282        for (int i = 1; i < layers.length; i++) {
283            extents = internalExtents(extents, getLayerExtents(resolution, layers[i]));
284            if (!isValidExtents(extents)) {
285                return null;
286            }
287        }
288
289        //get mask and adjust extents for filter
290        byte[][] mask;
291        int w = 0, h = 0;
292        double res = Double.parseDouble(resolution);
293        if (region != null) {
294            extents = internalExtents(extents, region.getBoundingBox());
295
296            if (!isValidExtents(extents)) {
297                return null;
298            }
299
300            h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
301            w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
302            mask = getRegionMask(res, extents, w, h, region);
303        } else if (envelopes != null) {
304            h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
305            w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
306            mask = getEnvelopeMaskAndUpdateExtents(resolution, res, extents, h, w, envelopes);
307            h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
308            w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
309        } else {
310            h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
311            w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
312            mask = getMask(res, extents, w, h);
313        }
314
315        //mkdir in index location
316        String newPath = null;
317        try {
318            newPath = AlaspatialProperties.getAnalysisWorkingDir() + System.currentTimeMillis() + java.io.File.separator;
319            File directory = new File(newPath);
320            directory.mkdir();
321        } catch (Exception e) {
322            e.printStackTrace();
323        }
324
325        //apply mask
326        for (int i = 0; i < layers.length; i++) {
327            applyMask(newPath, resolution, extents, w, h, mask, layers[i]);
328        }
329
330        //write extents file
331        writeExtents(extentsFilename, extents, w, h);
332
333        return newPath;
334    }
335
336    static double[][] internalExtents(double[][] e1, double[][] e2) {
337        double[][] internalExtents = new double[2][2];
338
339        internalExtents[0][0] = Math.max(e1[0][0], e2[0][0]);
340        internalExtents[0][1] = Math.max(e1[0][1], e2[0][1]);
341        internalExtents[1][0] = Math.min(e1[1][0], e2[1][0]);
342        internalExtents[1][1] = Math.min(e1[1][1], e2[1][1]);
343
344        return internalExtents;
345    }
346
347    static boolean isValidExtents(double[][] e) {
348        return e[0][0] < e[1][0] && e[0][1] < e[1][1];
349    }
350
351    static double[][] getLayerExtents(String resolution, String layer) {
352        double[][] extents = new double[2][2];
353        Grid g = Grid.getGrid(getLayerPath(resolution, layer));
354
355        extents[0][0] = g.xmin;
356        extents[0][1] = g.ymin;
357        extents[1][0] = g.xmax;
358        extents[1][1] = g.ymax;
359
360        return extents;
361    }
362
363    public static String getLayerPath(String resolution, String layer) {
364        String field = Layers.getFieldId(layer);
365
366        File file = new File(AlaspatialProperties.getAnalysisLayersDir() + File.separator + resolution + File.separator + field + ".grd");
367
368        //move up a resolution when the file does not exist at the target resolution
369        try {
370            while (!file.exists()) {
371                TreeMap<Double, String> resolutionDirs = new TreeMap<Double, String>();
372                for (File dir : new File(AlaspatialProperties.getAnalysisLayersDir()).listFiles()) {
373                    if (dir.isDirectory()) {
374                        try {
375                            resolutionDirs.put(Double.parseDouble(dir.getName()), dir.getName());
376                        } catch (Exception e) {
377                        }
378                    }
379                }
380
381                String newResolution = resolutionDirs.higherEntry(Double.parseDouble(resolution)).getValue();
382
383                if (newResolution.equals(resolution)) {
384                    break;
385                } else {
386                    resolution = newResolution;
387                    file = new File(AlaspatialProperties.getAnalysisLayersDir() + File.separator + resolution + File.separator + field + ".grd");
388                }
389            }
390        } catch (Exception e) {
391        }
392
393        String layerPath = AlaspatialProperties.getAnalysisLayersDir() + File.separator + resolution + File.separator + field;
394
395        if (new File(layerPath + ".grd").exists()) {
396            return layerPath;
397        } else {
398            //look for an analysis layer
399            String[] info = Client.getLayerIntersectDao().getConfig().getAnalysisLayerInfo(layer);
400            if (info != null) {
401                return info[1];
402            } else {
403                System.out.println("getLayerPath, cannot find for: " + layer + ", " + resolution);
404                return null;
405            }
406        }
407    }
408
409    static void applyMask(String dir, String resolution, double[][] extents, int w, int h, byte[][] mask, String layer) {
410        //layer output container
411        double[] dfiltered = new double[w * h];
412
413        //open grid and get all data
414        Grid grid = Grid.getGrid(getLayerPath(resolution, layer));
415        float[] d = grid.getGrid(); //get whole layer
416
417        //set all as missing values
418        for (int i = 0; i < dfiltered.length; i++) {
419            dfiltered[i] = Double.NaN;
420        }
421
422        double res = Double.parseDouble(resolution);
423
424        for (int i = 0; i < mask.length; i++) {
425            for (int j = 0; j < mask[0].length; j++) {
426                if (mask[i][j] > 0) {
427                    dfiltered[j + (h - i - 1) * w] = grid.getValues2(new double[][]{{j * res + extents[0][0], i * res + extents[0][1]}})[0];
428                }
429            }
430        }
431
432        grid.writeGrid(dir + layer, dfiltered,
433                extents[0][0],
434                extents[0][1],
435                extents[1][0],
436                extents[1][1],
437                res, res, h, w);
438    }
439
440    static void writeExtents(String filename, double[][] extents, int w, int h) {
441        if (filename != null) {
442            try {
443                FileWriter fw = new FileWriter(filename);
444                fw.append(String.valueOf(w)).append("\n");
445                fw.append(String.valueOf(h)).append("\n");
446                fw.append(String.valueOf(extents[0][0])).append("\n");
447                fw.append(String.valueOf(extents[0][1])).append("\n");
448                fw.append(String.valueOf(extents[1][0])).append("\n");
449                fw.append(String.valueOf(extents[1][1]));
450                fw.close();
451            } catch (Exception e) {
452                e.printStackTrace();
453            }
454        }
455    }
456
457    /**
458     * Get a region mask.
459     *
460     * Note: using decimal degree grid, probably should be EPSG900913 grid.
461     *
462     * @param res resolution as double
463     * @param extents extents as double[][] with [0][0]=xmin, [0][1]=ymin,
464     * [1][0]=xmax, [1][1]=ymax.
465     * @param h height as int.
466     * @param w width as int.
467     * @param region area for the mask as SimpleRegion.
468     * @return
469     */
470    private static byte[][] getRegionMask(double res, double[][] extents, int w, int h, SimpleRegion region) {
471        byte[][] mask = new byte[h][w];
472
473        //can also use region.getOverlapGridCells_EPSG900913
474        region.getOverlapGridCells(extents[0][0], extents[0][1], extents[1][0], extents[1][1], w, h, mask);
475        for (int i = 0; i < h; i++) {
476            for (int j = 0; j < w; j++) {
477                //double tx = (j + 0.5) * res + extents[0][0];
478                //double ty = (i + 0.5) * res + extents[0][1];
479                //if (region.isWithin_EPSG900913(tx, ty)) {
480                //    mask[i][j] = 1;
481                //}
482                if (mask[i][j] > 0) {
483                    mask[i][j] = 1;
484                }
485            }
486        }
487        return mask;
488    }
489
490    private static byte[][] getMask(double res, double[][] extents, int w, int h) {
491        byte[][] mask = new byte[h][w];
492        for (int i = 0; i < h; i++) {
493            for (int j = 0; j < w; j++) {
494                mask[i][j] = 1;
495            }
496        }
497        return mask;
498    }
499
500    /**
501     * Get a mask, 0=absence, 1=presence, for a given envelope and extents.
502     *
503     * @param resolution resolution as String.
504     * @param res resultions as double.
505     * @param extents extents as double[][] with [0][0]=xmin, [0][1]=ymin,
506     * [1][0]=xmax, [1][1]=ymax.
507     * @param h height as int.
508     * @param w width as int.
509     * @param envelopes
510     * @return mask as byte[][]
511     */
512    private static byte[][] getEnvelopeMaskAndUpdateExtents(String resolution, double res, double[][] extents, int h, int w, LayerFilter[] envelopes) {
513        byte[][] mask = new byte[h][w];
514
515        double[][] points = new double[h * w][2];
516        for (int i = 0; i < w; i++) {
517            for (int j = 0; j < h; j++) {
518                points[i + j * w][0] = (double) (extents[0][0] + (i + 0.5) * res);
519                points[i + j * w][1] = (double) (extents[0][1] + (j + 0.5) * res);
520                //mask[j][i] = 0;
521            }
522        }
523
524        for (int k = 0; k < envelopes.length; k++) {
525            LayerFilter lf = envelopes[k];
526
527            Grid grid = Grid.getGrid(getLayerPath(resolution, lf.getLayername()));
528
529            float[] d = grid.getValues3(points, 40960);
530
531            for (int i = 0; i < d.length; i++) {
532                if (lf.isValid(d[i])) {
533                    mask[i / w][i % w]++;
534                }
535            }
536        }
537
538        for (int i = 0; i < w; i++) {
539            for (int j = 0; j < h; j++) {
540                if (mask[j][i] == envelopes.length) {
541                    mask[j][i] = 1;
542                } else {
543                    mask[j][i] = 0;
544                }
545            }
546        }
547
548        //find internal extents
549        int minx = w;
550        int maxx = -1;
551        int miny = h;
552        int maxy = -1;
553        for (int i = 0; i < w; i++) {
554            for (int j = 0; j < h; j++) {
555                if (mask[j][i] > 0) {
556                    if (minx > i) {
557                        minx = i;
558                    }
559                    if (maxx < i) {
560                        maxx = i;
561                    }
562                    if (miny > j) {
563                        miny = j;
564                    }
565                    if (maxy < j) {
566                        maxy = j;
567                    }
568                }
569            }
570        }
571
572        //reduce the size of the mask
573        int nw = maxx - minx + 1;
574        int nh = maxy - miny + 1;
575        byte[][] smallerMask = new byte[nh][nw];
576        for (int i = minx; i < maxx; i++) {
577            for (int j = miny; j < maxy; j++) {
578                smallerMask[j - miny][i - minx] = mask[j][i];
579            }
580        }
581
582
583        //update extents, must never be larger than the original extents (res is not negative, minx maxx miny mazy are not negative and < w & h respectively
584        extents[0][0] = Math.max(extents[0][0] + minx * res,extents[0][0]); //min x value
585        extents[1][0] = Math.min(extents[1][0] - (w - maxx - 1) * res,extents[1][0]); //max x value
586        extents[0][1] = Math.max(extents[0][1] + miny * res,extents[0][1]); //min y value
587        extents[1][1] = Math.min(extents[1][1] - (h - maxy - 1) * res,extents[1][1]); //max y value
588
589        return smallerMask;
590    }
591
592    /**
593     * Write a diva grid to disk for the envelope, 0 = absence, 1 = presence.
594     *
595     * @param filename output filename for the grid as String.
596     * @param resolution target resolution in decimal degrees as String.
597     * @param envelopes envelope specification as LayerFilter[].
598     * @return area in sq km as double.
599     */
600    public static double makeEnvelope(String filename, String resolution, LayerFilter[] envelopes) {
601
602        //get extents for all layers
603        double[][] extents = getLayerExtents(resolution, envelopes[0].getLayername());
604        for (int i = 1; i < envelopes.length; i++) {
605            extents = internalExtents(extents, getLayerExtents(resolution, envelopes[i].getLayername()));
606            if (!isValidExtents(extents)) {
607                return -1;
608            }
609        }
610
611        double res = Double.parseDouble(resolution);
612        
613        //limit the size of the grid files that can be generated
614        while ((Math.abs(extents[0][1] - extents[1][0])/res) * (Math.abs(extents[0][0] - extents[1][0])/res) > AlaspatialProperties.getAnalysisLimitGridCells()*2.0) {
615            res = res * 2;
616        }
617        if (res != Double.parseDouble(resolution)) {
618            resolution = String.format("%f", res);
619        }
620        
621        //get mask and adjust extents for filter
622        byte[][] mask;
623        int w, h;
624        h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
625        w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
626        mask = getEnvelopeMaskAndUpdateExtents(resolution, res, extents, h, w, envelopes);
627        h = (int) Math.ceil((extents[1][1] - extents[0][1]) / res);
628        if(((int) Math.ceil((extents[1][1] + res - extents[0][1]) / res)) == h) {
629            extents[1][1] += res;
630        }
631        w = (int) Math.ceil((extents[1][0] - extents[0][0]) / res);
632        if(((int) Math.ceil((extents[1][0] + res - extents[0][0]) / res)) == w) {
633            extents[1][0] += res;
634        }
635        
636        float[] values = new float[w * h];
637        int pos = 0;
638        double areaSqKm = 0;
639        for (int i = h - 1; i >= 0; i--) {
640            for (int j = 0; j < w; j++) {
641                if(i < mask.length && j < mask[i].length) {
642                    values[pos] = mask[i][j];
643                    
644                    if (mask[i][j] > 0) {
645                        areaSqKm += SpatialUtil.cellArea(res, extents[0][1] + res * i);
646                    }
647                } else {
648                    values[pos] = 0;
649                }
650                pos++;
651            }
652        }
653
654        Grid grid = new Grid(getLayerPath(resolution, envelopes[0].getLayername()));
655
656        grid.writeGrid(filename, values,
657                extents[0][0],
658                extents[0][1],
659                extents[1][0],
660                extents[1][1],
661                res, res, h, w);
662
663        return areaSqKm;
664    }
665
666
667    /**
668     * Test if the layer filter is valid.
669     *
670     * The common problem is that a filter may refer to a layer that is not
671     * available.
672     *
673     * @param resolution target resolution as String.
674     * @param filter layer filter as LayerFilter[].
675     * @return true iff valid filter.
676     */
677    public static boolean isValidLayerFilter(String resolution, LayerFilter[] filter) {
678        for (LayerFilter lf : filter) {
679            if (GridCutter.getLayerPath(resolution, lf.getLayername()) == null) {
680                return false;
681            }
682        }
683        return true;
684    }
685
686    /**
687     * Determine the grid resolution that will be in use.
688     *
689     * @param layers list of layers to be used as String []
690     * @param resolution target resolution as String
691     * @return resolution that will be used
692     */
693    private static String confirmResolution(String[] layers, String resolution) {
694        try {
695            TreeMap<Double, String> resolutions = new TreeMap<Double, String>();
696            for (String layer : layers) {
697                String path = GridCutter.getLayerPath(resolution, layer);
698                int end, start;
699                if (path != null
700                        && ((end = path.lastIndexOf(File.separator)) > 0)
701                        && ((start = path.lastIndexOf(File.separator, end - 1)) > 0)) {
702                    String res = path.substring(start + 1, end);
703                    Double d = Double.parseDouble(res);
704                    if (d < 1) {
705                        resolutions.put(d, res);
706                    }
707                }
708            }
709            if (resolutions.size() > 0) {
710                resolution = resolutions.firstEntry().getValue();
711            }
712        } catch (Exception e) {
713            e.printStackTrace();
714        }
715        return resolution;
716    }
717}