au.org.ala.layers.grid.GridClassBuilder.java Source code

Java tutorial

Introduction

Here is the source code for au.org.ala.layers.grid.GridClassBuilder.java

Source

/**************************************************************************
 * Copyright (C) 2010 Atlas of Living Australia
 * All Rights Reserved.
 * <p>
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * <p>
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 ***************************************************************************/
package au.org.ala.layers.grid;

import au.org.ala.layers.dto.GridClass;
import au.org.ala.layers.intersect.Grid;
import au.org.ala.layers.util.SpatialUtil;
import com.vividsolutions.jts.geom.MultiPolygon;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.kml.KML;
import org.geotools.kml.KMLConfiguration;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.xml.Encoder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author Adam
 */
public class GridClassBuilder {

    final public static int[] colours = { 0x003366CC, 0x00DC3912, 0x00FF9900, 0x00109618, 0x00990099, 0x000099C6,
            0x00DD4477, 0x0066AA00, 0x00B82E2E, 0x00316395, 0x00994499, 0x0022AA99, 0x00AAAA11, 0x006633CC,
            0x00E67300, 0x008B0707, 0x00651067, 0x00329262, 0x005574A6, 0x003B3EAC, 0x00B77322, 0x0016D620,
            0x00B91383, 0x00F4359E, 0x009C5935, 0x00A9C413, 0x002A778D, 0x00668D1C, 0x00BEA413, 0x000C5922,
            0x00743411 };
    private static final Logger logger = Logger.getLogger(GridClassBuilder.class);

    public static void main(String[] args) {

        logger.info("args[0]=diva grid input file (do not include .grd or .gri)\n\n");

        if (args.length > 0) {

            //remove existing
            try {
                File f;

                if ((f = new File(args[0] + ".classes.json")).exists()) {
                    f.delete();
                }

                if ((f = new File(args[0])).exists() && f.isDirectory()) {
                    File[] fs = f.listFiles();
                    for (int i = 0; i < fs.length; i++) {
                        if (fs[i].isFile()) {
                            fs[i].delete();
                        }
                    }
                }

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }

            //build new
            try {
                buildFromGrid(args[0]);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    public static HashMap<Integer, GridClass> buildFromGrid(String filePath) throws IOException {
        File wktDir = new File(filePath);
        wktDir.mkdirs();

        int[] wktMap = null;

        //track values for the SLD
        ArrayList<Integer> maxValues = new ArrayList<Integer>();
        ArrayList<String> labels = new ArrayList<String>();

        HashMap<Integer, GridClass> classes = new HashMap<Integer, GridClass>();
        Properties p = new Properties();
        p.load(new FileReader(filePath + ".txt"));

        boolean mergeProperties = false;

        Map<String, Set<Integer>> groupedKeys = new HashMap<String, Set<Integer>>();
        Map<Integer, Integer> translateKeys = new HashMap<Integer, Integer>();
        Map<String, Integer> translateValues = new HashMap<String, Integer>();
        ArrayList<Integer> keys = new ArrayList<Integer>();
        for (String key : p.stringPropertyNames()) {
            try {
                int k = Integer.parseInt(key);
                keys.add(k);

                //grouping of property file keys by value
                String value = p.getProperty(key);
                Set<Integer> klist = groupedKeys.get(value);
                if (klist == null)
                    klist = new HashSet<Integer>();
                else
                    mergeProperties = true;
                klist.add(k);
                groupedKeys.put(value, klist);

                if (!translateValues.containsKey(value))
                    translateValues.put(value, translateValues.size() + 1);
                translateKeys.put(k, translateValues.get(value));

            } catch (NumberFormatException e) {
                logger.info("Excluding shape key '" + key + "'");
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        java.util.Collections.sort(keys);

        Grid g = new Grid(filePath);
        boolean generateWkt = false; //((long) g.nrows) * ((long) g.ncols) < (long) Integer.MAX_VALUE;

        if (mergeProperties) {
            g.replaceValues(translateKeys);

            if (!new File(filePath + ".txt.old").exists())
                FileUtils.moveFile(new File(filePath + ".txt"), new File(filePath + ".txt.old"));

            StringBuilder sb = new StringBuilder();
            for (String value : translateValues.keySet()) {
                sb.append(translateValues.get(value)).append("=").append(value).append('\n');
            }
            FileUtils.writeStringToFile(new File(filePath + ".txt"), sb.toString());

            return buildFromGrid(filePath);
        }

        if (generateWkt) {
            for (String name : groupedKeys.keySet()) {
                try {
                    Set<Integer> klist = groupedKeys.get(name);

                    String key = klist.iterator().next().toString();
                    int k = Integer.parseInt(key);

                    GridClass gc = new GridClass();
                    gc.setName(name);
                    gc.setId(k);

                    if (klist.size() == 1)
                        klist = null;

                    logger.info("getting wkt for " + filePath + " > " + key);

                    Map wktIndexed = Envelope.getGridSingleLayerEnvelopeAsWktIndexed(
                            filePath + "," + key + "," + key, klist, wktMap);

                    //write class wkt
                    File zipFile = new File(filePath + File.separator + key + ".wkt.zip");
                    ZipOutputStream zos = null;
                    try {
                        zos = new ZipOutputStream(new FileOutputStream(zipFile));
                        zos.putNextEntry(new ZipEntry(key + ".wkt"));
                        zos.write(((String) wktIndexed.get("wkt")).getBytes());
                        zos.flush();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    } finally {
                        if (zos != null) {
                            try {
                                zos.close();
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                    }
                    BufferedOutputStream bos = null;
                    try {
                        bos = new BufferedOutputStream(
                                new FileOutputStream(filePath + File.separator + key + ".wkt"));
                        bos.write(((String) wktIndexed.get("wkt")).getBytes());
                        bos.flush();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    } finally {
                        if (bos != null) {
                            try {
                                bos.close();
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                    }
                    logger.info("wkt written to file");
                    gc.setArea_km(SpatialUtil.calculateArea((String) wktIndexed.get("wkt")) / 1000.0 / 1000.0);

                    //store map
                    wktMap = (int[]) wktIndexed.get("map");

                    //write wkt index
                    FileWriter fw = null;
                    try {
                        fw = new FileWriter(filePath + File.separator + key + ".wkt.index");
                        fw.append((String) wktIndexed.get("index"));
                        fw.flush();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    } finally {
                        if (fw != null) {
                            try {
                                fw.close();
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                    }
                    //write wkt index a binary, include extents (minx, miny, maxx, maxy) and area (sq km)
                    int minPolygonNumber = 0;
                    int maxPolygonNumber = 0;

                    RandomAccessFile raf = null;
                    try {
                        raf = new RandomAccessFile(filePath + File.separator + key + ".wkt.index.dat", "rw");

                        String[] index = ((String) wktIndexed.get("index")).split("\n");

                        for (int i = 0; i < index.length; i++) {
                            if (index[i].length() > 1) {
                                String[] cells = index[i].split(",");
                                int polygonNumber = Integer.parseInt(cells[0]);
                                raf.writeInt(polygonNumber); //polygon number
                                int polygonStart = Integer.parseInt(cells[1]);
                                raf.writeInt(polygonStart); //character offset

                                if (i == 0) {
                                    minPolygonNumber = polygonNumber;
                                } else if (i == index.length - 1) {
                                    maxPolygonNumber = polygonNumber;
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    } finally {
                        if (raf != null) {
                            try {
                                raf.close();
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                    }

                    //for SLD
                    maxValues.add(gc.getMaxShapeIdx());
                    labels.add(name.replace("\"", "'"));
                    gc.setMinShapeIdx(minPolygonNumber);
                    gc.setMaxShapeIdx(maxPolygonNumber);

                    logger.info("getting multipolygon for " + filePath + " > " + key);
                    MultiPolygon mp = Envelope.getGridEnvelopeAsMultiPolygon(filePath + "," + key + "," + key);
                    gc.setBbox(mp.getEnvelope().toText().replace(" (", "(").replace(", ", ","));

                    classes.put(k, gc);

                    try {
                        //write class kml
                        zos = null;
                        try {
                            zos = new ZipOutputStream(
                                    new FileOutputStream(filePath + File.separator + key + ".kml.zip"));

                            zos.putNextEntry(new ZipEntry(key + ".kml"));
                            Encoder encoder = new Encoder(new KMLConfiguration());
                            encoder.setIndenting(true);
                            encoder.encode(mp, KML.Geometry, zos);
                            zos.flush();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            if (zos != null) {
                                try {
                                    zos.close();
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                }
                            }
                        }
                        logger.info("kml written to file");

                        final SimpleFeatureType TYPE = DataUtilities.createType("class",
                                "the_geom:MultiPolygon,id:Integer,name:String");
                        FeatureJSON fjson = new FeatureJSON();
                        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
                        SimpleFeature sf = featureBuilder.buildFeature(null);

                        //write class geojson
                        zos = null;
                        try {
                            zos = new ZipOutputStream(
                                    new FileOutputStream(filePath + File.separator + key + ".geojson.zip"));
                            zos.putNextEntry(new ZipEntry(key + ".geojson"));
                            featureBuilder.add(mp);
                            featureBuilder.add(k);
                            featureBuilder.add(name);

                            fjson.writeFeature(sf, zos);
                            zos.flush();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            if (zos != null) {
                                try {
                                    zos.close();
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                }
                            }
                        }
                        logger.info("geojson written to file");

                        //write class shape file
                        File newFile = new File(filePath + File.separator + key + ".shp");
                        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
                        Map<String, Serializable> params = new HashMap<String, Serializable>();
                        params.put("url", newFile.toURI().toURL());
                        params.put("create spatial index", Boolean.FALSE);
                        ShapefileDataStore newDataStore = null;
                        try {
                            newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
                            newDataStore.createSchema(TYPE);
                            newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84);
                            Transaction transaction = new DefaultTransaction("create");
                            String typeName = newDataStore.getTypeNames()[0];
                            SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
                            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
                            featureStore.setTransaction(transaction);
                            List<SimpleFeature> features = new ArrayList<SimpleFeature>();

                            DefaultFeatureCollection collection = new DefaultFeatureCollection();
                            collection.addAll(features);
                            featureStore.setTransaction(transaction);

                            features.add(sf);
                            featureStore.addFeatures(collection);
                            transaction.commit();
                            transaction.close();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            if (newDataStore != null) {
                                try {
                                    newDataStore.dispose();
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                }
                            }
                        }

                        zos = null;
                        try {
                            zos = new ZipOutputStream(
                                    new FileOutputStream(filePath + File.separator + key + ".shp.zip"));
                            //add .dbf .shp .shx .prj
                            String[] exts = { ".dbf", ".shp", ".shx", ".prj" };
                            for (String ext : exts) {
                                zos.putNextEntry(new ZipEntry(key + ext));
                                FileInputStream fis = null;
                                try {
                                    fis = new FileInputStream(filePath + File.separator + key + ext);
                                    byte[] buffer = new byte[1024];
                                    int size;
                                    while ((size = fis.read(buffer)) > 0) {
                                        zos.write(buffer, 0, size);
                                    }
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                } finally {
                                    if (fis != null) {
                                        try {
                                            fis.close();
                                        } catch (Exception e) {
                                            logger.error(e.getMessage(), e);
                                        }
                                    }
                                }
                                //remove unzipped files
                                new File(filePath + File.separator + key + ext).delete();
                            }
                            zos.flush();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            if (zos != null) {
                                try {
                                    zos.close();
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                }
                            }
                        }
                        logger.info("shape file written to zip");
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }

            //write polygon mapping
            g.writeGrid(filePath + File.separator + "polygons", wktMap, g.xmin, g.ymin, g.xmax, g.ymax, g.xres,
                    g.yres, g.nrows, g.ncols);

            //copy the header file to get it exactly the same, but change the data type
            copyHeaderAsInt(filePath + ".grd", filePath + File.separator + "polygons.grd");
        } else {
            //build classes without generating polygons
            Map<Float, float[]> info = new HashMap<Float, float[]>();
            for (int j = 0; j < keys.size(); j++) {
                info.put(keys.get(j).floatValue(), new float[] { 0, Float.NaN, Float.NaN, Float.NaN, Float.NaN });
            }

            g.getClassInfo(info);

            for (int j = 0; j < keys.size(); j++) {
                int k = keys.get(j);
                String key = String.valueOf(k);

                String name = p.getProperty(key);

                GridClass gc = new GridClass();
                gc.setName(name);
                gc.setId(k);

                //for SLD
                maxValues.add(Integer.valueOf(key));
                labels.add(name.replace("\"", "'"));
                gc.setMinShapeIdx(Integer.valueOf(key));
                gc.setMaxShapeIdx(Integer.valueOf(key));

                float[] stats = info.get(keys.get(j).floatValue());

                //only include if area > 0
                if (stats[0] > 0) {
                    gc.setBbox("POLYGON((" + stats[1] + " " + stats[2] + "," + stats[1] + " " + stats[4] + ","
                            + stats[3] + " " + stats[4] + "," + stats[3] + " " + stats[2] + "," + stats[1] + " "
                            + stats[2] + "))");

                    gc.setArea_km((double) stats[0]);
                    classes.put(k, gc);
                }
            }
        }

        //write sld
        exportSLD(filePath + File.separator + "polygons.sld", new File(filePath + ".txt").getName(), maxValues,
                labels);

        writeProjectionFile(filePath + File.separator + "polygons.prj");

        //write .classes.json
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(new File(filePath + ".classes.json"), classes);

        return classes;
    }

    static void exportSLD(String filename, String name, ArrayList<Integer> maxValues, ArrayList<String> labels) {
        StringBuffer sld = new StringBuffer();
        /* header */
        sld.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sld.append(
                "<sld:StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" xmlns:sld=\"http://www.opengis.net/sld\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\" version=\"1.0.0\">");
        sld.append("<sld:NamedLayer>");
        sld.append("<sld:Name>raster</sld:Name>");
        sld.append(" <sld:UserStyle>");
        sld.append("<sld:Name>raster</sld:Name>");
        sld.append("<sld:Title>A very simple color map</sld:Title>");
        sld.append("<sld:Abstract>A very basic color map</sld:Abstract>");
        sld.append("<sld:FeatureTypeStyle>");
        sld.append(" <sld:Name>name</sld:Name>");
        sld.append("<sld:FeatureTypeName>Feature</sld:FeatureTypeName>");
        sld.append(" <sld:Rule>");
        sld.append("   <sld:RasterSymbolizer>");
        sld.append(" <sld:Geometry>");
        sld.append(" <ogc:PropertyName>geom</ogc:PropertyName>");
        sld.append(" </sld:Geometry>");
        sld.append(" <sld:ChannelSelection>");
        sld.append(" <sld:GrayChannel>");
        sld.append("   <sld:SourceChannelName>1</sld:SourceChannelName>");
        sld.append(" </sld:GrayChannel>");
        sld.append(" </sld:ChannelSelection>");
        sld.append(" <sld:ColorMap type=\"intervals\">");

        //sort labels
        List<String> sortedLabels = new ArrayList<String>(labels);
        Collections.sort(sortedLabels);

        /* outputs */
        sld.append("\n<sld:ColorMapEntry color=\"#ffffff\" opacity=\"0\" quantity=\"1\"/>\n");
        for (int j = 0; j < sortedLabels.size(); j++) {
            int i = 0;
            while (i < labels.size()) {
                if (labels.get(i).equals(sortedLabels.get(j)))
                    break;
                i++;
            }
            sld.append("<sld:ColorMapEntry color=\"#" + getHexColour(colours[i % colours.length]) + "\" quantity=\""
                    + (maxValues.get(i) + 1) + ".0\" label=\"" + labels.get(i) + "\" opacity=\"1\"/>\r\n");
        }

        /* footer */
        sld.append(
                "</sld:ColorMap></sld:RasterSymbolizer></sld:Rule></sld:FeatureTypeStyle></sld:UserStyle></sld:NamedLayer></sld:StyledLayerDescriptor>");

        /* write */
        FileWriter fw = null;
        try {
            fw = new FileWriter(filename);
            fw.append(sld.toString());
            fw.flush();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }

    static String getHexColour(int colour) {
        String s = Integer.toHexString(colour);
        while (s.length() > 6) {
            s = s.substring(1);
        }
        while (s.length() < 6) {
            s = "0" + s;
        }
        return s;
    }

    private static void writeProjectionFile(String filename) {
        FileWriter spWriter = null;
        try {
            spWriter = new FileWriter(filename);

            StringBuffer sbProjection = new StringBuffer();
            sbProjection.append("GEOGCS[\"WGS 84\", ").append("\n");
            sbProjection.append("    DATUM[\"WGS_1984\", ").append("\n");
            sbProjection.append("        SPHEROID[\"WGS 84\",6378137,298.257223563, ").append("\n");
            sbProjection.append("            AUTHORITY[\"EPSG\",\"7030\"]], ").append("\n");
            sbProjection.append("        AUTHORITY[\"EPSG\",\"6326\"]], ").append("\n");
            sbProjection.append("    PRIMEM[\"Greenwich\",0, ").append("\n");
            sbProjection.append("        AUTHORITY[\"EPSG\",\"8901\"]], ").append("\n");
            sbProjection.append("    UNIT[\"degree\",0.01745329251994328, ").append("\n");
            sbProjection.append("        AUTHORITY[\"EPSG\",\"9122\"]], ").append("\n");
            sbProjection.append("    AUTHORITY[\"EPSG\",\"4326\"]] ").append("\n");

            //spWriter.write("spname, longitude, latitude \n");
            spWriter.append(sbProjection.toString());
            spWriter.flush();

        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (spWriter != null) {
                try {
                    spWriter.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }

    private static void copyHeaderAsInt(String src, String dst) {
        BufferedReader br = null;
        FileWriter fw = null;
        try {
            br = new BufferedReader(new FileReader(src));
            fw = new FileWriter(dst);
            String line;
            while ((line = br.readLine()) != null) {
                if (line.startsWith("DataType=")) {
                    fw.write("DataType=INT\n");
                } else {
                    fw.write(line);
                    fw.write("\n");
                }
            }
            fw.flush();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
            if (fw != null) {
                try {
                    fw.close();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }
}