All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wikibrain.spatial.WikiBrainShapeFile Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
package org.wikibrain.spatial;

import org.apache.commons.io.FileUtils;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.h2.util.StringUtils;
import org.opengis.feature.simple.SimpleFeatureType;
import org.supercsv.io.CsvMapReader;
import org.supercsv.prefs.CsvPreference;
import org.wikibrain.utils.WpIOUtils;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A utility wrapper around GeoTool's shape file class.
 * Also contains many static helper methods.
 *
 * Several of the methods contain variants that take a layer and ones that do not.
 * The ones that do not take a layer default to the "first" layer in the shapefile.
 *
 * @author Shilad Sen
 */
public class WikiBrainShapeFile {
    private static final Logger LOG = LoggerFactory.getLogger(WikiBrainShapeFile.class);

    public static final String [] EXTENSIONS = new String[] { ".shp", ".shx", ".dbf" };

    public static final String WB_MAP_EXTENSINO = ".wbmapping.csv";

    // Ends with ".shp" extension
    private final File file;
    private final String encoding;

    private DataStore dataStore;

    /**
     * Creates a new shapefile wrapper associated with the given file.
     * @param file Must end with ".shp"
     */
    public WikiBrainShapeFile(File file) {
        this(file, "UTF-8");
    }

    /**
     * Creates a new shapefile wrapper associated with the given file.
     * @param file Must end with ".shp"
     */
    public WikiBrainShapeFile(File file, String encoding) {
        ensureHasShpExtension(file);
        this.file = file;
        this.encoding = encoding;
    }

    public synchronized void initDataStoreIfNecessary() throws IOException {
        if (this.dataStore == null) {
            this.dataStore = fileToDataStore(file, encoding);
        }
    }

    static class KeyAndScore implements Comparable {
        String key;
        Double score;

        KeyAndScore(String key, Double score) {
            this.key = key;
            this.score = score;
        }

        @Override
        public int compareTo(KeyAndScore o) {
            int r = -1 * score.compareTo(o.score);
            if (r == 0) {
                r = key.compareTo(o.key);
            }
            return r;
        }

        @Override
        public String toString() {
            return "{" + "key='" + key + '\'' + ", score=" + score + '}';
        }
    }

    /**
     * Reads in a mapping from shapefile key to title for all entries with status != U
     * @return
     */
    public Map readMapping() throws IOException {
        HashMap mapping = new HashMap();
        if (!hasMappingFile()) {
            throw new IOException("No mapping file found: " + getMappingFile());
        }
        CsvMapReader reader = new CsvMapReader(
                WpIOUtils.openBufferedReader(getMappingFile()),
                CsvPreference.STANDARD_PREFERENCE
        );

        // Read in the data and scores
        Map> scores = new HashMap>();
        String [] header = reader.getHeader(true);
        while (true) {
            Map row = reader.read(header);
            if (row == null) {
                break;
            }
            if (!row.get("WB_STATUS").equalsIgnoreCase("U")) {
                String key = row.get("WB_KEY");
                String title = row.get("WB_TITLE");
                double score = Double.valueOf(row.get("WB_SCORE"));
                if (StringUtils.isNullOrEmpty(title)) {
                    continue;
                }
                if (!scores.containsKey(title)) {
                    scores.put(title, new ArrayList());
                }
                scores.get(title).add(new KeyAndScore(key, score));
            }
        }

        for (String title : scores.keySet()) {
            List titleScores = scores.get(title);
            Collections.sort(titleScores);
            mapping.put(titleScores.get(0).key, title);
            if (titleScores.size() > 1) {
                LOG.warn("duplicate keys for title " + title + ": " + titleScores);
            }
        }

        return mapping;
    }

    /**
     * Returns all feature names (i.e. column ids) for the specified layer.
     * @param layer
     * @return
     * @throws IOException
     */
    public List getFeatureNames(String layer) throws IOException {
        initDataStoreIfNecessary();
        SimpleFeatureCollection features = getFeatureCollection(layer);
        SimpleFeatureType type = features.getSchema();
        List fields = new ArrayList();
        for (int i = 0; i < type.getAttributeCount(); i++) {
            fields.add(type.getDescriptor(i).getLocalName());
        }
        return fields;
    }

    /**
     * Returns all feature names (i.e. column ids) for the default layer.
     * @return
     * @throws IOException
     */
    public List getFeatureNames() throws IOException {
        return getFeatureNames(getDefaultLayer());
    }

    /**
     * Returns an iterator over rows for the default layer.
     * @return
     * @throws IOException
     */
    public SimpleFeatureIterator getFeatureIter() throws IOException {
        return getFeatureCollection().features();
    }

    /**
     * Returns an iterator over rows for the specified layer.
     * @return
     * @throws IOException
     */
    public SimpleFeatureIterator getFeatureIter(String layer) throws IOException {
        return getFeatureCollection(layer).features();
    }

    public SimpleFeatureCollection getFeatureCollection(String layer) throws IOException {
        initDataStoreIfNecessary();
        SimpleFeatureSource featureSource = dataStore.getFeatureSource(layer);
        return featureSource.getFeatures();
    }

    public SimpleFeatureCollection getFeatureCollection() throws IOException {
        return getFeatureCollection(getDefaultLayer());
    }

    /**
     * Returns the name of the default layer
     * @return
     * @throws IOException
     */
    public String getDefaultLayer() throws IOException {
        initDataStoreIfNecessary();
        return dataStore.getTypeNames()[0];
    }


    public WikiBrainShapeFile move(File dest) throws IOException {
        ensureHasShpExtension(dest);
        dest.getParentFile().mkdirs();
        for (String ext : EXTENSIONS) {
            File extDest = getAlternateExtension(dest, ext);
            FileUtils.deleteQuietly(extDest);
            getAlternateExtension(file, ext).renameTo(extDest);
        }
        return new WikiBrainShapeFile(dest, encoding);
    }

    public File getMappingFile() {
        return getAlternateExtension(file, WB_MAP_EXTENSINO);
    }

    public boolean hasMappingFile() {
        return getMappingFile().isFile();
    }

    public File getFile() {
        return file;
    }

    public List getComponentFiles() {
        List files = new ArrayList();
        for (String ext : EXTENSIONS) {
            files.add(getAlternateExtension(file, ext));
        }
        if (hasMappingFile()) {
            files.add(getMappingFile());
        }
        return files;
    }

    public boolean hasComponentFiles() {
        for (File f : getComponentFiles()) {
            if (!f.isFile()) return false;
        }
        return true;
    }

    public DataStore getDataStore() {
        return dataStore;
    }

    public static DataStore fileToDataStore(File file) throws IOException {
        return fileToDataStore(file, "utf-8");
    }

    public static DataStore fileToDataStore(File file, String encoding) throws IOException {
        Map map = new HashMap();
        try {
            map.put("url", file.toURI().toURL());
        } catch (MalformedURLException e) {
            throw new IOException(e);
        }
        map.put(ShapefileDataStoreFactory.DBFCHARSET.getName(), encoding);
        return  DataStoreFinder.getDataStore(map);
    }

    public static boolean exists(File file) {
        ensureHasShpExtension(file);
        return new WikiBrainShapeFile(file).hasComponentFiles();
    }

    public static File getAlternateExtension(File file, String ext) {
        ensureHasShpExtension(file);
        String prefix = file.toString().substring(0, file.toString().length() - ".shp".length());
        return new File(prefix + ext);
    }

    public static boolean hasShpExtension(File file) {
        return file.toString().toLowerCase().endsWith(".shp");
    }

    private static void ensureHasShpExtension(File file) {
        if (!hasShpExtension(file)) {
            throw new IllegalArgumentException("File " + file + " does not have .shp extension");
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy