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

org.integratedmodelling.engine.geospace.Geospace Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2015:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but without any warranty; without even the implied warranty of
 *    merchantability or fitness for a particular purpose.  See the
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.geospace;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.factory.GeoTools;
import org.geotools.factory.Hints;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.referencing.CRS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.geotools.referencing.factory.PropertyAuthorityFactory;
import org.geotools.referencing.factory.ReferencingFactoryContainer;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IState;
import org.integratedmodelling.api.modelling.ISubject;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.engine.geospace.extents.SpaceExtent;
import org.integratedmodelling.engine.geospace.gis.GISOperations;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.w3c.dom.Node;

//import java.util.ArrayList;

public class Geospace {

    /**
     * Makes all CRS respect a X,Y arrangement. Without this, things get incredibly
     * messy and wrong.
     */
    static {
        System.setProperty("org.geotools.referencing.forceXY", "true");
    }

    JCS _wcsCache = null;
    JCS _wfsCache = null;

    // public static class NS {
    //
    // public static final String ELEVATION = "im.geo:ElevationSeaLevel";
    // public static final String DEGREE_SLOPE = "im.geo:DegreeSlope";
    // public static final String PERCENT_SLOPE = "im.geo:PercentSlope";
    // public static final String RADIANS_SLOPE = "im.geo:RadiansSlope";
    // }

    private IConcept shapeType;
    private IConcept pointType;
    private IConcept lineStringType;
    private IConcept polygonType;
    private IConcept multiPointType;
    private IConcept multiLineStringType;
    private IConcept multiPolygonType;
    // private ISemanticObject areaLocationInstance;
    // private ISemanticObject rasterGridInstance;
    // private ISemanticObject spatialCoverageInstance;
    private IConcept arealLocationType;
    private IConcept rasterGridObservable;
    private IConcept spatialCoverageObservable;
    private IConcept subdividedSpaceObservable;
    // private IConcept spaceObservable;
    private IConcept gridClassifierType;
    private IConcept spaceDomain;

    private static String hasBoundingBoxPropertyID;
    private static String hasCentroidPropertyID;

    private static IConcept    rasterSpaceType;
    static final public String PLUGIN_ID = "org.integratedmodelling.thinklab.geospace";

    public static final String X_RANGE_OFFSET                = "geospace:hasXRangeOffset";
    public static final String X_RANGE_MAX                   = "geospace:hasXRangeMax";
    public static final String Y_RANGE_OFFSET                = "geospace:hasYRangeOffset";
    public static final String Y_RANGE_MAX                   = "geospace:hasYRangeMax";
    public static final String LAT_LOWER_BOUND               = "geospace:hasLatLowerBound";
    public static final String LON_LOWER_BOUND               = "geospace:hasLonLowerBound";
    public static final String LAT_UPPER_BOUND               = "geospace:hasLatUpperBound";
    public static final String LON_UPPER_BOUND               = "geospace:hasLonUpperBound";
    public static final String CRS_CODE                      = "geospace:hasCoordinateReferenceSystem";
    public static final String COVERAGE_SOURCE_URL           = "geospace:hasSourceURL";
    public static final String RASTER_GRID_OBSERVABLE        = "geospace:ContinuousRegularSpatialGrid";
    public static final String SHAPE_COVERAGE_OBSERVABLE     = "geospace:PolygonSpatialCoverage";
    public static final String PREFERRED_CRS_PROPERTY        = "geospace.preferred.crs";
    public static final String HAS_VALUE_ATTRIBUTE           = "geospace:hasValueAttribute";
    public static final String HAS_SOURCE_LINK_ATTRIBUTE     = "geospace:hasSourceLinkAttribute";
    public static final String HAS_TARGET_LINK_ATTRIBUTE     = "geospace:hasTargetLinkAttribute";
    public static final String HAS_TRANSFORMATION_EXPRESSION = "geospace:hasTransformation";
    public static final String HAS_ATTRIBUTE_URL             = "geospace:hasAttributeUrl";
    public static final String RASTER_GRID                   = "geospace:RasterGrid";
    public static final String AREAL_LOCATION                = "geospace:RasterGrid";
    public static final String GRID_CLASSIFIER               = "geospace:GridClassifier";
    public static final String CLASSIFIED_GRID               = "geospace:ClassifiedGrid";
    public static final String GRID_CLASSIFICATION_MODEL     = "geospace:GridClassification";
    public static final String HAS_FILTER_PROPERTY           = "geospace:hasFilter";

    // the projection to use if we need meters
    public static final String EPSG_PROJECTION_METERS  = "EPSG:3005";
    public static final String EPSG_PROJECTION_DEFAULT = "EPSG:4326";
    public static final String EPSG_PROJECTION_GOOGLE  = "EPSG:3857";

    // property to add new CRS by hand in property file
    public static final String CUSTOM_CRS_PROPERTY = "geospace.crs.";

    // projections not in the main repository inserted through properties
    static HashMap localCRS = new HashMap();

    /*
     * if not null, we have a preferred crs in the properties, and we solve
     * all conflicts by translating to it. 
     */
    CoordinateReferenceSystem preferredCRS = null;
    CoordinateReferenceSystem metersCRS    = null;
    CoordinateReferenceSystem googleCRS    = null;
    // CoordinateReferenceSystem geoCRSstraight = null;

    // /*
    // * we maintain a collection of gazetteers that plugins can install. The lookupFeature() function
    // * will search all of them.
    // */
    // HashMap gazetteers = new HashMap();
    private CoordinateReferenceSystem defaultCRS = null;
    private Boolean                   _useSquareCellsM;

    static private Geospace _this;

    public static Geospace get() {
        if (_this == null) {
            try {
                _this = new Geospace();
            } catch (KlabException e) {
                throw new KlabRuntimeException(e);
            }
        }
        return _this;
    }

    void registerAdditionalCRS() throws KlabException {

        URL epsg = null;

        File epp = new File(KLAB.CONFIG.getDataPath() + File.separator + "epsg.properties");
        if (epp.exists()) {
            try {
                epsg = epp.toURI().toURL();
            } catch (MalformedURLException e) {
                throw new KlabIOException(e);
            }
        }

        if (epsg != null) {
            Hints hints = new Hints(Hints.CRS_AUTHORITY_FACTORY, PropertyAuthorityFactory.class);
            ReferencingFactoryContainer referencingFactoryContainer = ReferencingFactoryContainer
                    .instance(hints);
            PropertyAuthorityFactory factory;
            try {
                factory = new PropertyAuthorityFactory(referencingFactoryContainer, Citations
                        .fromName("EPSG"), epsg);
                ReferencingFactoryFinder.addAuthorityFactory(factory);
            } catch (IOException e) {
                throw new KlabIOException(e);
            }
        }
    }

    public JCS getWFSCache() throws KlabException {

        if (_wfsCache == null) {

            try {
                _wfsCache = JCS.getInstance("wfs");
            } catch (CacheException e) {
                throw new KlabIOException(e);
            }

        }
        return _wfsCache;
    }

    public JCS getWCSCache() throws KlabException {

        if (_wcsCache == null) {

            try {
                _wcsCache = JCS.getInstance("wcs");
            } catch (CacheException e) {
                throw new KlabIOException(e);
            }

        }
        return _wcsCache;
    }

    private Geospace() throws KlabException {

        /*
         * TODO put all these class names into global strings in NS
         */
        spaceDomain = KLAB.KM.getConcept(NS.SPACE_DOMAIN);
        pointType = KLAB.KM.getConcept("geospace:Point");
        lineStringType = KLAB.KM.getConcept("geospace:LineString");
        polygonType = KLAB.KM.getConcept("geospace:Polygon");
        multiPointType = KLAB.KM.getConcept("geospace:MultiPoint");
        multiLineStringType = KLAB.KM.getConcept("geospace:MultiLineString");
        multiPolygonType = KLAB.KM.getConcept("geospace:MultiPolygon");
        arealLocationType = KLAB.KM.getConcept("geospace:ArealLocation");
        rasterGridObservable = KLAB.KM.getConcept(RASTER_GRID_OBSERVABLE);
        spatialCoverageObservable = KLAB.KM.getConcept(SHAPE_COVERAGE_OBSERVABLE);
        gridClassifierType = KLAB.KM.getConcept(GRID_CLASSIFIER);

        shapeType = KLAB.KM.getConcept("geospace:SpatialRecord");

        hasBoundingBoxPropertyID = "geospace:hasBoundingBox";
        hasCentroidPropertyID = "geospace:hasCentroid";

        try {
            registerAdditionalCRS();

            metersCRS = CRS.decode(EPSG_PROJECTION_METERS, true);
            defaultCRS = CRS.decode(EPSG_PROJECTION_DEFAULT, true);
            googleCRS = CRS.decode(EPSG_PROJECTION_GOOGLE, true);

            // CRSAuthorityFactory factory = CRS.getAuthorityFactory(true);
            // geoCRSstraight = factory.createCoordinateReferenceSystem("EPSG:4326");

        } catch (Exception e) {
            throw new KlabException(e);
        }

        /*
         * create preferred CRS if one is specified. Highly advisable to set one if hybrid data
         * are used.
         */
        if (KLAB.CONFIG.getProperties().containsKey(PREFERRED_CRS_PROPERTY)) {
            preferredCRS = getCRSFromID(KLAB.CONFIG.getProperties().getProperty(PREFERRED_CRS_PROPERTY));
        }
    }

    public CoordinateReferenceSystem getPreferredCRS() {
        return preferredCRS;
    }

    public CoordinateReferenceSystem getGoogleCRS() {
        return googleCRS;
    }

    // /**
    // * Return a lat/lon CRS that is guaranteed to transform data to coordinates that have longitude on
    // * the X axis.
    // *
    // * @return
    // */
    // public CoordinateReferenceSystem getStraightGeoCRS() {
    // return geoCRSstraight;
    // }

    /**
     * The geotools implementation is unclear and doesn't seem to work, so 
     * I put this function here and we'll only have to fix it in one place.
     * 
     * @param crs
     * @param useDefault 
     * @return crs identifier
     */
    public static String getCRSIdentifier(CoordinateReferenceSystem crs, boolean useDefault) {

        if (crs != null) {
            try {
                return CRS.lookupIdentifier(crs, true);
            } catch (FactoryException e) {
                throw new KlabRuntimeException(e);
            }
        }

        return useDefault ? KLAB.CONFIG.getProperties().getProperty(PREFERRED_CRS_PROPERTY) : null;

    }

    public CoordinateReferenceSystem getMetersCRS() {
        return metersCRS;
    }

    /**
     * Get the appropriate (sort of) UTM projection for the passed WGS84 point.
     * 
     * @param x
     * @param y
     * @return CRS for meters in region
     * @throws KlabValidationException
     */
    public CoordinateReferenceSystem getMetersCRS(double x, double y) throws KlabValidationException {

        int base_srid = y < 0 ? 32700 : 32600;
        int out_srid = x == 180.0 ? base_srid + 60 : base_srid + (int) Math.floor((x + 186.0) / 6.0);

        CoordinateReferenceSystem ret = getCRSFromID("EPSG:" + out_srid);

        return ret == null ? metersCRS : ret;
    }

    public IConcept Point() {
        return pointType;
    }

    public IConcept LineString() {
        return lineStringType;
    }

    public IConcept Polygon() {
        return polygonType;
    }

    public IConcept MultiPoint() {
        return multiPointType;
    }

    public IConcept MultiLineString() {
        return multiLineStringType;
    }

    public IConcept MultiPolygon() {
        return multiPolygonType;
    }

    public IConcept Shape() {
        return shapeType;
    }

    // public ISemanticObject absoluteArealLocationInstance(IOntology session) {
    // return areaLocationInstance;
    // }
    //
    // public ISemanticObject absoluteRasterGridInstance(IOntology session) {
    // return rasterGridInstance;
    // }

    public IConcept ArealLocation() {
        return arealLocationType;
    }

    public static String hasBoundingBox() {
        return hasBoundingBoxPropertyID;
    }

    public static String hasCentroid() {
        return hasCentroidPropertyID;
    }

    public boolean handlesFormat(String format) {
        // TODO add remaining support formats as necessary
        return format.equals("shp") || format.equals("tif") || format.equals("tiff");
    }

    public Hints getGeotoolsHints() {
        // TODO we need to create appropriate hints at initialization, using the plugin's
        // properties.
        return GeoTools.getDefaultHints();
    }

    public void notifyConfigurationNode(Node n) {
        // TODO Auto-generated method stub

    }

    public static IConcept RasterObservationSpace() {
        return rasterSpaceType;
    }

    // public ISemanticObject RasterGridObservable() {
    //
    // if (rasterGridInstance == null) {
    // try {
    // rasterGridInstance = Thinklab.get().entify(PolyList.list(rasterGridObservable));
    // } catch (ThinklabException e) {
    // throw new ThinklabRuntimeException(e);
    // }
    // }
    // return rasterGridInstance;
    // }

    public IConcept SubdividedSpaceObservable() {
        return subdividedSpaceObservable;
    }

    //
    // public IConcept SpaceObservable() {
    // return spaceObservable;
    // }

    public void setPreferredCRS(CoordinateReferenceSystem crs) {
        preferredCRS = crs;
    }

    // public ISemanticObject SpatialCoverageObservable() {
    //
    // if (spatialCoverageInstance == null) {
    // try {
    // spatialCoverageInstance = Thinklab.get().entify(PolyList.list(spatialCoverageObservable));
    // } catch (ThinklabException e) {
    // throw new ThinklabRuntimeException(e);
    // }
    // }
    // return spatialCoverageInstance;
    // }

    public IConcept GridClassifier() {
        return gridClassifierType;
    }

    // /**
    // * Add a gazetteer to the collection.
    // * @param g
    // */
    // public void addGazetteer(String id, IGazetteer g) {
    // gazetteers.put(id,g);
    // }

    public CoordinateReferenceSystem getDefaultCRS() {
        return defaultCRS;
    }

    /**
     * Lookup a feature name through all existing gazetteers. If stopWhenFound is true, return
     * after the first lookup that succeeds.
     * 
     * @param name
     * @return
     * @throws ThinklabException
     */
    // public IQueryResult lookupFeature(String name)
    // throws ThinklabException {
    //
    // MultipleQueryResult ret =
    // new MultipleQueryResult(new QueryString(name));
    //
    // // sort them every time, we're not going to have a million of these.
    // IGazetteer[] gazz = new IGazetteer[gazetteers.size()];
    // int i = 0;
    // for (IGazetteer g : gazetteers.values())
    // gazz[i++] = g;
    //
    // Arrays.sort(gazz, new Comparator() {
    // @Override
    // public int compare(IGazetteer o1, IGazetteer o2) {
    // return o1.getPriority() - o2.getPriority();
    // }
    // });
    //
    // for (IGazetteer g : gazz) {
    // ret.add(g.query(g.parseQuery(name)));
    // }
    //
    // return ret;
    // }

    // public Collection listKnownFeatures() {
    //
    // ArrayList ret = new ArrayList();
    // //
    // // for (IGazetteer g : gazetteers.values()) {
    // // g.getKnownNames(ret);
    // // }
    //
    // return ret;
    // }
    //
    // /**
    // * Get your engine here, passing the necessary configuration properties.
    // *
    // * @param subject
    // * @param properties
    // * @return
    // * @throws ThinklabException
    // */
    // public void createGazetteer(Extension ext, Properties properties) throws ThinklabException {

    // String id = getParameter(ext, "id");
    //
    // /*
    // * find the declaring plugin so we can find data and files in its classpath
    // */
    // ThinklabPlugin resourceFinder = null;
    // try {
    // resourceFinder =
    // (ThinklabPlugin)getManager().getPlugin(ext.getDeclaringPluginDescriptor().getId());
    // } catch (PluginLifecycleException e) {
    // throw new ThinklabValidationException("can't determine the plugin that created the gazetteer "+ id);
    // }
    //
    // Properties p = new Properties();
    // p.putAll(properties);
    //
    // /*
    // * may point to a property file in the config dir
    // */
    // String pfile = getParameter(ext, "property-file");
    // if (pfile != null) {
    // File f = new File(resourceFinder.getConfigPath() + "/" + pfile);
    // if (!f.exists()) {
    //
    // /*
    // * exit silently, just print a warning
    // */
    // logger().warn("gazetteer " + id + " cannot find the property file " +
    // pfile + "; initialization aborted");
    // return;
    // }
    // Properties pp = new Properties();
    // try {
    // pp.load(new FileInputStream(f));
    // } catch (Exception e) {
    // throw new ThinklabIOException(e);
    // }
    // p.putAll(pp);
    // }
    //
    // /*
    // * can also specify properties inline
    // */
    // for (Extension.Parameter aext : ext.getParameters("property")) {
    // String name = aext.getSubParameter("name").valueAsString();
    // String value = aext.getSubParameter("value").valueAsString();
    // p.setProperty(name, value);
    // }
    //
    // log.info("creating gazetteer " + id);
    // IGazetteer ret = (IGazetteer) getHandlerInstance(ext, "class");
    // ret.initialize(p);
    // gazetteers.put(id, ret);
    // }

    /**
     * Load the gazetteers specified in the passed plugin and set them in the
     * engine repository. In addition, look in plugin data dir for subdirectories
     * of gazetters/. Any subdir in it is supposed to contain a gazetteer.properties
     * file that will be used to initialize a PostgisGazetteer, and (optionally) 
     * a set of shapefiles that will be loaded if their 
     * creation date is more recent than the date of last access to the 
     * gazetteer.
     *
     *  Must be called explicitly by plugins declaring gazetteers.
     * 
     * @param pluginId
     * @throws ThinklabException
     * @throws PluginLifecycleException 
     */
    // public void loadGazetteers(String pluginId) throws ThinklabException {
    // //
    // // for (Extension ext : getPluginExtensions(pluginId, PLUGIN_ID, "gazetteer")) {
    // // createGazetteer(ext, getProperties());
    // // }
    // }

    //
    // public void loadGazetteersFromDirectory(File dir) throws ThinklabException {
    //
    // File pdir = new File(dir + File.separator + "gazetteers");
    //
    // if (!(pdir.exists() && pdir.isDirectory()))
    // return;
    //
    // String[] files = pdir.list();
    //
    // for (String file : files) {
    // File gdir = new File(pdir + File.separator + file);
    // if (gdir.isDirectory()) {
    // IGazetteer gaz = readGazetteerFromDirectory(gdir);
    // if (gaz != null) {
    // gazetteers.put(file, gaz);
    // }
    // }
    // }
    // }

    // private IGazetteer readGazetteerFromDirectory(File gdir) throws ThinklabException {
    //
    // // File props = new File(gdir + File.separator + "gazetteer.properties");
    // IGazetteer ret = null;
    //
    // if (props.exists()) {
    //
    // Properties pp = new Properties();
    // try {
    // pp.load(new FileInputStream(props));
    // } catch (Exception e) {
    // throw new ThinklabIOException(e);
    // }
    //
    // logger().info("loading gazetteer from " + gdir);
    //
    // ret = new PostgisGazetteer();
    // ret.initialize(pp);
    //
    // long mtime = new Date().getTime();
    // File lock = new File(gdir + File.separator + ".last_access");
    //
    // if (lock.exists()) {
    // mtime = lock.lastModified();
    // }
    //
    // for (String ff : gdir.list()) {
    // if (ff.endsWith(".shp")) {
    //
    // File shp = new File(gdir + File.separator + ff);
    // File lck = new File(MiscUtilities.changeExtension(shp.toString(), "lck"));
    //
    // if (!lck.exists()) {
    //
    // logger().info("adding gazetteer source " + ff);
    //
    // try {
    // ret.importLocations(shp.toURI().toURL().toString(), null);
    // } catch (MalformedURLException e) {
    // throw new ThinklabValidationException(e);
    // }
    //
    // try {
    // FileUtils.touch(lck);
    // } catch (IOException e) {
    // throw new ThinklabIOException(e);
    // }
    // }
    // }
    // }
    //
    // try {
    // FileUtils.touch(lock);
    // } catch (IOException e) {
    // throw new ThinklabIOException(e);
    // }
    // }
    //
    // return ret;
    // }

    // /**
    // * Find a specific gazetteer by name, complain if not found
    // *
    // * @param id
    // * @return
    // * @throws ThinklabResourceNotFoundException
    // */
    // public IGazetteer requireGazetteer(String id) throws ThinklabResourceNotFoundException {
    // IGazetteer ret = gazetteers.get(id);
    // if (ret == null)
    // throw new ThinklabResourceNotFoundException("gazetteer " + id + " is not registered");
    // return ret;
    // }

    // /**
    // * Find a specific gazetteer by name
    // *
    // * @param id
    // * @return
    // * @throws ThinklabResourceNotFoundException
    // */
    // public IGazetteer retrieveGazetteer(String id) {
    // return gazetteers.get(id);
    // }

    /**
     * Returns true if the passed reference system assumes the X axis to be longitude (east-west).
     * @param ccr
     * @return true if x is horizontal
     */
    public static boolean isLongitudeX(CoordinateReferenceSystem ccr) {
        return !ccr.getCoordinateSystem().getAxis(0).getDirection().equals(AxisDirection.NORTH);
    }

    /**
     * This method decides the CRS to use when they differ in merged extents.
     * TODO at the moment it just returns the preferred CRS in the plugin, so
     * even equal CRS get transformed.
     * 
     * @param crs1
     * @param crs2
     * @return crs
     */
    public static CoordinateReferenceSystem chooseCRS(CoordinateReferenceSystem crs1, CoordinateReferenceSystem crs2) {

        CoordinateReferenceSystem ret = Geospace.get().getPreferredCRS();

        if (ret == null) {
            ret = crs1;
            Geospace.get().setPreferredCRS(ret);
        }

        return ret;
    }

    /**
     * Should be used throughout instead of CRS.decode().
     * 
     * @param crsId
     * @return crs
     */
    public static CoordinateReferenceSystem getCRSFromID(String crsId) {

        CoordinateReferenceSystem ret = localCRS.get(crsId);

        if (ret == null) {
            try {
                ret = CRS.decode(crsId, true);
                localCRS.put(crsId, ret);
            } catch (Exception e) {
                throw new KlabRuntimeException(e);
            }
        }

        return ret;
    }

    public boolean squareCellsM() {
        if (_useSquareCellsM == null) {
            _useSquareCellsM = Boolean.parseBoolean(KLAB.CONFIG.getProperties()
                    .getProperty("square.cells.meters", "false"));
        }
        return _useSquareCellsM;
    }

    /**
     * Get the concept that will identify the domain of all spatial extents in this implementation.
     * This type should be returned by IExtent.getDomainConcept() in all spatial extents capable of
     * mediating to each other.
     * 
     * @return space domain
     */
    public IConcept SpatialDomain() {
        return spaceDomain;
    }

    public CoordinateReferenceSystem getLatLonCRS() {
        // TODO improve
        return getDefaultCRS();
    }

    /**
     * Persist a spatially distributed (and possibly temporally distributed) state in
     * the passed file. Should be a GIS map of suitable format; if time is distributed,
     * interpret the file as a directory and create one map per time instant.
     * 
     * @param state
     * @param file
     * @throws KlabException 
     */
    public void persistState(IState state, File file, Iterable locators)
            throws KlabException {
        saveCoverage(state, file, locators);
    }

    private void saveCoverage(IState state, File file, Iterable locators)
            throws KlabException {

        SpaceExtent space = (SpaceExtent) state.getSpace();
        if (space.getGrid() != null) {

            GridCoverage2D coverage = GISOperations.stateToCoverage(state, locators);
            if (coverage != null) {
                if (!file.toString().endsWith(".tif") && !file.toString().endsWith(".tiff")) {
                    file = new File(file + ".tif");
                }
                GridCoverageWriter writer = new GeoTiffFormat().getWriter(file);
                try {
                    writer.write(coverage, null);
                } catch (Exception e) {
                    throw new KlabIOException(e);
                }
            }
        }
    }

    public void persistSubject(ISubject obs, File file) {
        // TODO Auto-generated method stub

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy