001/*
002 * Copyright (c) 2014-2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2018-07-24 17:17:37 +0000 (Tue, 24 Jul 2018) $' 
007 * '$Revision: 34705 $'
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.conversions;
030
031import org.geotools.coverage.grid.GridCoverage2D;
032import org.geotools.data.simple.SimpleFeatureCollection;
033import org.geotools.geometry.jts.ReferencedEnvelope;
034import org.geotools.process.vector.VectorToRasterProcess;
035import org.kepler.gis.actor.GetBoundingBox;
036import org.kepler.gis.data.RasterToken;
037import org.kepler.gis.data.VectorToken;
038import org.kepler.gis.util.RasterUtilities;
039import org.opengis.feature.simple.SimpleFeatureType;
040
041import ptolemy.actor.TypedIOPort;
042import ptolemy.actor.lib.Transformer;
043import ptolemy.actor.parameters.PortParameter;
044import ptolemy.data.IntToken;
045import ptolemy.data.StringToken;
046import ptolemy.data.Token;
047import ptolemy.data.type.BaseType;
048import ptolemy.kernel.CompositeEntity;
049import ptolemy.kernel.util.IllegalActionException;
050import ptolemy.kernel.util.NameDuplicationException;
051import ptolemy.kernel.util.SingletonAttribute;
052
053/** An actor that converts a vector/feature data set into a raster.
054 * 
055 *  @author Daniel Crawl
056 *  @version $Id: VectorToRaster.java 34705 2018-07-24 17:17:37Z crawl $
057 */
058public class VectorToRaster extends Transformer {
059
060    public VectorToRaster(CompositeEntity container, String name)
061            throws IllegalActionException, NameDuplicationException {
062
063        super(container, name);
064        
065        input.setTypeEquals(VectorToken.VECTOR);
066        new SingletonAttribute(input, "_showName");
067
068        output.setTypeEquals(RasterToken.RASTER);
069        
070        attributeName = new PortParameter(this, "attributeName");
071        attributeName.setTypeEquals(BaseType.STRING);
072        attributeName.setStringMode(true);
073        new SingletonAttribute(attributeName.getPort(), "_showName");
074
075        height = new PortParameter(this, "height");
076        height.setTypeEquals(BaseType.INT);
077        new SingletonAttribute(height.getPort(), "_showName");
078        height.setToken(String.valueOf(100));
079
080        width = new PortParameter(this, "width");
081        width.setTypeEquals(BaseType.INT);
082        new SingletonAttribute(width.getPort(), "_showName");
083        width.setToken(String.valueOf(100));
084        
085        title = new PortParameter(this, "title");
086        title.setTypeEquals(BaseType.STRING);
087        title.setStringMode(true);
088        new SingletonAttribute(title.getPort(), "_showName");
089        title.setToken("title");
090        
091        reference = new TypedIOPort(this, "reference", true, false);
092        reference.setTypeEquals(RasterToken.RASTER);
093        new SingletonAttribute(reference, "_showName");
094        
095    }
096    
097    @Override
098    public void fire() throws IllegalActionException {
099        
100        super.fire();
101        
102        attributeName.update();
103        height.update();
104        width.update();
105        title.update();
106        
107        String attributeNameStr = ((StringToken)attributeName.getToken()).stringValue();
108        if(attributeNameStr.trim().isEmpty()) {
109            throw new IllegalActionException(this, "Attribute name must be specified.");
110        }
111        
112        String titleStr = ((StringToken)title.getToken()).stringValue();
113        if(titleStr.trim().isEmpty()) {
114            throw new IllegalActionException(this, "Title must be specified.");
115        }
116
117        RasterToken referenceRaster = null;
118        boolean heightValid = false;
119        boolean widthValid = false;
120        int widthVal = 0;
121        int heightVal = 0;
122        if(reference.numberOfSources() > 0) {
123            referenceRaster = (RasterToken)reference.get(0);
124        } else {
125            Token token = width.getToken();
126            if(token != null) {
127                widthVal = ((IntToken)width.getToken()).intValue();
128                if(widthVal < 1) {
129                    throw new IllegalActionException(this, "Width must be greater than 0.");
130                }
131                widthValid = true;
132            }
133            
134            token = height.getToken();
135            if(token != null) {
136                heightVal = ((IntToken)height.getToken()).intValue();
137                if(heightVal < 1) {
138                    throw new IllegalActionException(this, "Height must be greater than 0.");
139                }
140                heightValid = true;
141            }
142        
143        }
144                
145        
146        SimpleFeatureCollection features = ((VectorToken)input.get(0)).getVectors();
147        
148        SimpleFeatureType schema = features.getSchema();
149        
150        if(schema == null) {
151            throw new IllegalActionException(this, "Features do not have schema.");
152        }
153        
154        if(schema.getType(attributeNameStr) == null) {
155            throw new IllegalActionException(this, "Attribute " +
156                    attributeNameStr + " not found in input vector collection.");
157        }
158
159        ReferencedEnvelope envelope = null;
160        
161        if(referenceRaster != null) {
162            envelope = GetBoundingBox.getBoundingBox(referenceRaster);
163            Integer[] sizes = RasterUtilities.getGridSize(referenceRaster);
164            widthVal = sizes[0];
165            heightVal = sizes[1];
166            
167            //System.out.println("env ref raster: " + referenceRaster.reader().getOriginalEnvelope());
168            
169        } else {
170            envelope = features.getBounds();
171
172            if(!widthValid) {
173                //widthVal = Math.abs(Double.valueOf(envelope.getMaxX() - envelope.getMinX()).intValue());
174                widthVal = (int) envelope.getWidth();
175            }
176            
177            if(!heightValid) {
178                //heightVal = Math.abs(Double.valueOf(envelope.getMaxY() - envelope.getMinY()).intValue());
179                heightVal = (int) envelope.getHeight();
180            }
181        }        
182
183        VectorToRasterProcess process = new VectorToRasterProcess();
184
185        GridCoverage2D coverage = 
186                process.execute(features, widthVal, heightVal, titleStr,
187                    attributeNameStr, envelope, null);
188
189        //System.out.println("env vector: " + features.getBounds());
190        //System.out.println("env out raster: " + coverage.getEnvelope());
191        
192        output.broadcast(new RasterToken(coverage));        
193    }
194    
195    @Override
196    public void preinitialize() throws IllegalActionException {
197        super.preinitialize();
198        
199        if(reference.numberOfSources() > 0) {
200            if(height.getPort().numberOfSources() > 0) {
201                throw new IllegalActionException(this, "Reference and height ports cannot be both used.");
202            } else if(width.getPort().numberOfSources() > 0) {
203                throw new IllegalActionException(this, "Reference and width ports cannot be both used.");                
204            }
205        }
206        
207    }
208    
209
210    /** The attribute in the features to use as the raster values. */
211    public PortParameter attributeName;
212    
213    /** The height of the raster in pixels. If not specified, 
214     *  the height of the vector bounding box is used.
215     */
216    public PortParameter height;
217    
218    /** The width of the raster in pixels. If not specified, the width of
219     *  the vector bounding box is used.
220     */
221    public PortParameter width;
222    
223    /** The title of the raster. */
224    public PortParameter title;
225    
226    /** Raster to use for height, width, and cell size. */
227    public TypedIOPort reference;
228}