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

org.integratedmodelling.engine.visualization.VisualizationFactory 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.visualization;

import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.integratedmodelling.api.data.IExport;
import org.integratedmodelling.api.data.IExport.Aggregation;
import org.integratedmodelling.api.data.IExport.Format;
import org.integratedmodelling.api.data.IProbabilityDistribution;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IObservation;
import org.integratedmodelling.api.modelling.IClassification;
import org.integratedmodelling.api.modelling.IDirectObservation;
import org.integratedmodelling.api.modelling.IMeasuringObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IScale.Locator;
import org.integratedmodelling.api.modelling.IState;
import org.integratedmodelling.api.modelling.ISubject;
import org.integratedmodelling.api.modelling.visualization.IMedia;
import org.integratedmodelling.api.modelling.visualization.IViewport;
import org.integratedmodelling.api.modelling.visualization.IVisualizationFactory;
import org.integratedmodelling.common.beans.responses.ValueSummary;
import org.integratedmodelling.common.data.IndexedCategoricalDistribution;
import org.integratedmodelling.common.knowledge.ObservationGroup;
import org.integratedmodelling.common.owl.Knowledge;
import org.integratedmodelling.common.states.State;
import org.integratedmodelling.common.storage.ProbabilityStorage;
import org.integratedmodelling.common.utils.ZipUtils;
import org.integratedmodelling.common.visualization.Viewport;
import org.integratedmodelling.common.vocabulary.ObservableSemantics;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.coverage.vector.VectorCoverage;
import org.integratedmodelling.engine.geospace.gis.GISOperations;
import org.integratedmodelling.engine.time.Time;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.springframework.http.MediaType;

import com.google.common.io.Files;
import com.google.common.primitives.Doubles;

public class VisualizationFactory extends
        org.integratedmodelling.common.visualization.VisualizationFactory implements
        IVisualizationFactory {

    private static VisualizationFactory _this = null;

    public static VisualizationFactory get() {
        if (_this == null) {
            _this = new VisualizationFactory();
        }
        return _this;
    }

    public double[] getStateDataAsNumbers(IState state, Iterable locators) {

        double[] ret = new double[(int) state.getValueCount()];
        IClassification classification = getClassification(state);
        List ls = new ArrayList<>();
        for (IScale.Locator l : locators) {
            ls.add(l);
        }

        for (int n : state.getScale().getIndex(ls.toArray(new Locator[ls.size()]))) {

            /**
             * If a specific extent offset is needed, e.g. the offset in space, the
             * following can be used, which will return the spatial offset for the given
             * overall offset. The reason for not having specific getSpatialOffset() or
             * getTemporalOffset is that there can be additional extents beyond time and
             * space, although these are not used at the moment.
             */
            int i = state.getScale().getExtentOffset(state.getScale().getSpace(), n);
            Double d = Double.NaN;
            Object o = ((State) state).getValue(n);

            if (o instanceof Number) {
                d = ((Number) o).doubleValue();
            } else if (o instanceof IndexedCategoricalDistribution) {
                d = ((IndexedCategoricalDistribution) o).getMean();
            } else if (o instanceof Boolean) {
                d = ((Boolean) o) ? 1.0 : 0.0;
            } else if (o instanceof IConcept) {
                if (classification != null) {
                    d = classification.getNumericCode((IConcept) o);
                }
            } else if (o != null) {
                throw new KlabRuntimeException("internal: unexpected state value in VisualizationFactory.getStateData");
            }

            ret[i] = d;
        }

        return ret;
    }

    public double[] getStateDataAsNumbers(IState state) {

        double[] ret = new double[(int) state.getValueCount()];
        IClassification classification = getClassification(state);

        for (int i = 0; i < state.getValueCount(); i++) {

            Double d = Double.NaN;
            Object o = ((State) state).getValue(i);

            if (o instanceof Number) {
                d = ((Number) o).doubleValue();
            } else if (o instanceof IndexedCategoricalDistribution) {
                d = ((IndexedCategoricalDistribution) o).getMean();
            } else if (o instanceof Boolean) {
                d = ((Boolean) o) ? 1.0 : 0.0;
            } else if (o instanceof IConcept) {
                if (classification != null) {
                    d = classification.getNumericCode((IConcept) o);
                }
            } else if (o != null) {
                throw new KlabRuntimeException("internal: unexpected state value in VisualizationFactory.getStateData");
            }

            ret[i] = d;
        }

        return ret;
    }

    public float[] getStateDataAsFloats(IState state) {

        float[] ret = new float[(int) state.getValueCount()];
        for (int i = 0; i < state.getValueCount(); i++) {

            Double d = Double.NaN;
            Object o = ((State) state).getValue(i);

            if (o instanceof Number) {
                d = ((Number) o).doubleValue();
            } else if (o instanceof IndexedCategoricalDistribution) {
                d = ((IndexedCategoricalDistribution) o).getMean();
            } else if (o instanceof Boolean) {
                d = ((Boolean) o) ? 1.0 : 0.0;
            } else if (o != null) {
                throw new KlabRuntimeException("internal: unexpected state value in VisualizationFactory.getStateData");
            }

            ret[i] = d.floatValue();
        }

        return ret;
    }

    @Override
    public IMedia getMedia(IObservation observation, IScale.Index index, IViewport viewport, String mimeType, Map options) {

        MediaType type = MediaType.valueOf(mimeType);

        if (type.isCompatibleWith(MediaType.IMAGE_PNG)) {
            return new ImageMedia(observation, index, viewport, type, options);
        }
        return null;
    }

    public Object persist(IObservation obs, File file, Object... options)
            throws KlabException {

        Object ret = null;
        
        /*
         * parse back options. TODO may assume that anything else is a key,value pair for
         * the media that take it, but for now let's skip the painful coding.
         */
        List locators = new ArrayList<>();
        Viewport viewport = null;

        IExport.Aggregation aggregation = IExport.Aggregation.AVERAGE;
        IExport.Format format = IExport.Format.SCIENTIFIC_DATASET;

        for (Object o : options) {
            if (o instanceof IScale.Locator) {
                locators.add((Locator) o);
            } else if (o instanceof Viewport) {
                viewport = (Viewport) o;
            } else if (o instanceof IExport.Format) {
                format = (Format) o;
            } else if (o instanceof IExport.Aggregation) {
                aggregation = (Aggregation) o;
            }
        }

        if (format == Format.VIDEO) {
            if (obs instanceof IState && obs.getScale().isSpatiallyDistributed()
                    && obs.getScale().isTemporallyDistributed()) {
                VideoMedia vm = new VideoMedia(obs, viewport, null);
                try {
                    FileUtils.copyFile(vm.getFile(), file);
                } catch (IOException e) {
                    throw new KlabIOException(e);
                }
            }
        } else {

            if (obs instanceof IState) {
                if (aggregation != Aggregation.TOTAL || !obs.getScale().isTemporallyDistributed()) {
                    if (obs.getScale().isSpatiallyDistributed()) {
                        Geospace.get().persistState((IState) obs, file, locators);
                    } else if (obs.getScale().isTemporallyDistributed()) {
                        Time.get().persistState((IState) obs, file, locators);
                    }
                } else {
                    if (aggregation == Aggregation.TOTAL) {
                        if (obs.getScale().getSpace() != null && obs.getScale().getSpace().getGrid() != null) {
                            /*
                             * it's temporally explicit. Get an aggregated state.
                             */
                            GridCoverage2D coverage = GISOperations.aggregateStateToCoverage((IState) obs);
                            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);
                            }
                        } else {
                            /*
                             * TODO non-grid temporally distributed - shapes w/default attribute
                             */
                        }
                    }
                }

            } else if (obs instanceof ISubject) {

                ISubject subject = (ISubject)obs;
                
                if (format == Format.STATE_COLLECTION_FILE) {
                    
                    File tempDir = Files.createTempDir();

                    for (IState s : subject.getStates()) {
                        if (s.isSpatiallyDistributed()) {
                            File outfile = new File(tempDir + File.separator
                                    + ((ObservableSemantics) s.getObservable().getSemantics()).getExportFileName() + ".tif");
                            VisualizationFactory.get().persist(s, outfile, false, options);
                        }
                    }

                    ZipUtils.zip(file, tempDir, false, false);
                    
                } else {

                    persistSubject((ISubject) obs, file);
                }
            } else if (obs instanceof ObservationGroup) {
                
                /*
                 * should be a shapefile or a csv
                 */
                if (file.toString().endsWith(".shp")) {
                    VectorCoverage vcov = new VectorCoverage(obs.getType().getLocalName().toLowerCase());
                    for (IObservation o : ((ObservationGroup)obs)) {
                        if (o instanceof IDirectObservation) {
                            vcov.add((IDirectObservation) o);
                        }
                    }
                    ret = vcov.write(file);
                    
                } else if (file.toString().endsWith(".csv")) {
                    /*
                     * TODO
                     */
                }
                
                
            }
        }
        
        return ret;
        
    }

    private void persistSubject(ISubject obs, File file) {

        // TODO

        /*
         * Make temp dir
         */

        /*
         * export OWL dataset semantics
         */

        /*
         * export provenance and PDF report
         */

        /*
         * If structured, export each state appropriately; otherwise if any states exist,
         * produce .csv file with values.
         */

        /*
         * divide up subjects into types and produce overall view (CSV or shapefile) for
         * each type
         */

        /*
         * do same with event timeline and processes
         */

        /*
         * for each subject with internal structure, export recursively in its own
         * directory
         */

    }

    public ValueSummary describeValue(IState state, Object o) {

        ValueSummary ret = new ValueSummary();

        if (o == null || (o instanceof Double && Double.isNaN((Double) o))) {
            o = "No data";
        } else if (o instanceof IndexedCategoricalDistribution) {

            ret.setDistribution(Doubles.asList(((IndexedCategoricalDistribution) o).getData()));
            ret.setRanges(Doubles.asList(((IndexedCategoricalDistribution) o).getRanges()));
            ret.setUncertainty(((IndexedCategoricalDistribution) o).getUncertainty());

            if (state.getStorage() instanceof ProbabilityStorage) {
                IConcept likelyClass = ((ProbabilityStorage) state.getStorage())
                        .getMostLikelyClass((IProbabilityDistribution) o);
                if (likelyClass != null) {
                    ret.setMostLikelyClass(((Knowledge) likelyClass).asText());
                }
            }

            o = "m=" +
                    NumberFormat.getInstance().format(((IndexedCategoricalDistribution) o).getMean())
                    + ", s=" +
                    NumberFormat.getInstance().format(((IndexedCategoricalDistribution) o).getUncertainty());

        } else if (o instanceof Boolean) {
            o = state.getObservable().getSemantics().getType().getLocalName()
                    + ((Boolean) o ? " present" : " absent");
        } else if (o instanceof IConcept) {
            o = ((IConcept) o).getLocalName();
        } else if (o instanceof Number) {
            o = NumberFormat.getInstance().format(o);
        } else {
            o = o.toString();
        }

        if (state.getObserver() instanceof IMeasuringObserver) {
            o = o + " " + ((IMeasuringObserver) state.getObserver()).getUnit();
        }

        ret.setDescription(o.toString());
        return ret;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy