001/*
002 * Copyright (c) 2018 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2018-08-22 18:17:06 +0000 (Wed, 22 Aug 2018) $' 
007 * '$Revision: 34708 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.gis.actor.calc;
030
031import org.geotools.data.DataUtilities;
032import org.geotools.data.simple.SimpleFeatureCollection;
033import org.geotools.data.simple.SimpleFeatureIterator;
034import org.kepler.gis.data.VectorToken;
035import org.opengis.feature.simple.SimpleFeature;
036
037import com.vividsolutions.jts.geom.Geometry;
038
039import ptolemy.actor.TypedAtomicActor;
040import ptolemy.kernel.CompositeEntity;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.actor.TypedIOPort;
044
045/** Subtract one geometry from one or more others.
046 * 
047 * @author Daniel Crawl
048 * @version $Id: Difference.java 34708 2018-08-22 18:17:06Z crawl $
049 */
050public class Difference extends TypedAtomicActor {
051
052
053    public Difference(CompositeEntity container, String name)
054            throws IllegalActionException, NameDuplicationException {
055        super(container, name);
056        
057        input1 = new TypedIOPort(this, "input1", true, false);
058        input1.setTypeEquals(VectorToken.VECTOR);
059        
060        input2 = new TypedIOPort(this, "input2", true, false);
061        input2.setTypeEquals(VectorToken.VECTOR);
062
063        output = new TypedIOPort(this, "output", false, true);
064        output.setTypeEquals(VectorToken.VECTOR);
065
066    }
067    
068    @Override
069    public void fire() throws IllegalActionException {
070        
071        super.fire();
072        
073        SimpleFeatureCollection features1 = ((VectorToken)(input1).get(0)).getVectors();
074        
075        // make a copy since we're going to modify it.
076        features1 = DataUtilities.collection(features1);
077        
078        SimpleFeatureCollection features2 = ((VectorToken)(input2).get(0)).getVectors();
079        
080        if(features2.size() == 0) {
081            throw new IllegalActionException(this, "Input 2 has no features.");
082        } else if(features2.size() > 1) {
083            throw new IllegalActionException(this, "Input 2 has more than one feature.");
084        }
085        
086        Geometry geom2 = null;
087        
088        try(SimpleFeatureIterator iter = features2.features()) {
089            SimpleFeature feature = iter.next();
090            Object geom = feature.getDefaultGeometry();
091            if(!(geom instanceof Geometry)) {
092                throw new IllegalActionException(this, "Input 2 has unknown type of geometry.");
093            }
094            geom2 = (Geometry)geom;
095        }
096        
097        try(SimpleFeatureIterator iter = features1.features()) {
098            while(iter.hasNext()) {
099                SimpleFeature feature = iter.next();
100                Object geom = feature.getDefaultGeometry();
101                if(!(geom instanceof Geometry)) {
102                    throw new IllegalActionException(this, "Input 1 has unknown type of geometry.");
103                }
104                Geometry geomDiff = ((Geometry)geom).difference(geom2);
105                feature.setDefaultGeometry(geomDiff);
106            }
107        }
108        
109        output.broadcast(new VectorToken(features1));        
110    }
111    
112    @Override
113    public void preinitialize() throws IllegalActionException {
114        
115        super.preinitialize();
116        
117        if(input1.numberOfSources() == 0) {
118            throw new IllegalActionException(input1, "Input 1 must be connected.");
119        }
120        
121        if(input2.numberOfSources() == 0) {
122            throw new IllegalActionException(input2, "Input 2 must be connected.");
123        }
124        
125    }
126    
127    /** Vector data containing geometries from which to be subtracted. */
128    public TypedIOPort input1;
129    
130    /** Vector containing single geometry to subtract. */
131    public TypedIOPort input2;
132    
133    /** Vector data from input1 with the geometries replaced by the difference. */
134    public TypedIOPort output;
135
136}