001/*
002 * Copyright (c) 2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-12-21 19:25:28 +0000 (Mon, 21 Dec 2015) $' 
007 * '$Revision: 34354 $'
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.bbox;
030
031import org.geotools.geometry.jts.ReferencedEnvelope;
032import org.geotools.referencing.CRS;
033import org.kepler.gis.data.BoundingBoxToken;
034import org.opengis.referencing.FactoryException;
035import org.opengis.referencing.crs.CoordinateReferenceSystem;
036
037import ptolemy.actor.TypedAtomicActor;
038import ptolemy.actor.TypedIOPort;
039import ptolemy.actor.parameters.PortParameter;
040import ptolemy.data.DoubleToken;
041import ptolemy.data.StringToken;
042import ptolemy.data.Token;
043import ptolemy.data.type.BaseType;
044import ptolemy.kernel.CompositeEntity;
045import ptolemy.kernel.util.Attribute;
046import ptolemy.kernel.util.IllegalActionException;
047import ptolemy.kernel.util.NameDuplicationException;
048import ptolemy.kernel.util.SingletonAttribute;
049import ptolemy.kernel.util.Workspace;
050
051/** Create a bounding box.
052 * 
053 *  @author Daniel Crawl
054 *  @version $Id: CreateBoundingBox.java 34354 2015-12-21 19:25:28Z crawl $
055 */
056public class CreateBoundingBox extends TypedAtomicActor {
057
058    /** Create a new CreateBoundingBox in a container with the specified name. */
059    public CreateBoundingBox(CompositeEntity container, String name)
060            throws IllegalActionException, NameDuplicationException {
061        super(container, name);
062        
063        maxX = new PortParameter(this, "maxX");
064        maxX.setTypeEquals(BaseType.DOUBLE);
065        maxX.getPort().setTypeEquals(BaseType.DOUBLE);
066        new SingletonAttribute(maxX.getPort(), "_showName");
067
068        maxY = new PortParameter(this, "maxY");
069        maxY.setTypeEquals(BaseType.DOUBLE);
070        maxY.getPort().setTypeEquals(BaseType.DOUBLE);
071        new SingletonAttribute(maxY.getPort(), "_showName");
072
073        minX = new PortParameter(this, "minX");
074        minX.setTypeEquals(BaseType.DOUBLE);
075        minX.getPort().setTypeEquals(BaseType.DOUBLE);
076        new SingletonAttribute(minX.getPort(), "_showName");
077
078        minY = new PortParameter(this, "minY");
079        minY.setTypeEquals(BaseType.DOUBLE);
080        minY.getPort().setTypeEquals(BaseType.DOUBLE);
081        new SingletonAttribute(minY.getPort(), "_showName");
082        
083        crs = new PortParameter(this, "crs");
084        crs.setTypeEquals(BaseType.STRING);
085        crs.setStringMode(true);
086        crs.getPort().setTypeEquals(BaseType.STRING);
087        new SingletonAttribute(crs.getPort(), "_showName");
088        
089        crs.setToken("EPSG:4326");
090        crs.addChoice("EPSG:26911");
091        
092        output = new TypedIOPort(this, "output", false, true);
093        output.setTypeEquals(BoundingBoxToken.BOUNDING_BOX);
094    }
095    
096    
097    @Override
098    public void attributeChanged(Attribute attribute) throws IllegalActionException {
099        
100        if(attribute == crs) {
101            Token token = crs.getToken();
102            String crsStr = null;
103            if(token != null) {
104                crsStr = ((StringToken)token).stringValue().trim();
105            }
106
107            if(crsStr == null || crsStr.isEmpty()) {
108                _crsWasEmpty = true;
109                crsStr = "EPSG:4326";
110            } else {
111                _crsWasEmpty = false;
112            }
113
114            try {
115                _crs = CRS.decode(crsStr);
116            } catch (FactoryException e) {
117                throw new IllegalActionException(this, e, "Error decoding " + crsStr);
118            }
119        } else {
120            super.attributeChanged(attribute);
121        }
122    }
123
124    @Override
125    public Object clone(Workspace workspace) throws CloneNotSupportedException {
126        CreateBoundingBox newObject = (CreateBoundingBox) super.clone(workspace);
127        newObject._crs = null;
128        newObject._crsWasEmpty = false;
129        return newObject;
130    }
131    
132    @Override
133    public void fire() throws IllegalActionException {
134        
135        super.fire();
136        
137        maxX.update();
138        Token token = maxX.getToken();
139        if(token == null) {
140            throw new IllegalActionException(this, "Must provide maxX.");
141        }
142        double maxXVal = ((DoubleToken)token).doubleValue();
143        
144        maxY.update();
145        token = maxY.getToken();
146        if(token == null) {
147            throw new IllegalActionException(this, "Must provide maxY.");
148        }
149        double maxYVal = ((DoubleToken)token).doubleValue();
150        
151        minX.update();
152        token = minX.getToken();
153        if(token == null) {
154            throw new IllegalActionException(this, "Must provide minX.");
155        }
156        double minXVal = ((DoubleToken)token).doubleValue();
157        
158        minY.update();
159        token = minY.getToken();
160        if(token == null) {
161            throw new IllegalActionException(this, "Must provide minY.");
162        }
163        double minYVal = ((DoubleToken)token).doubleValue();
164        
165        // sanity checks
166        if(minXVal > maxXVal) {
167            throw new IllegalActionException(this, "minX must be less than maxX.");
168        }
169        
170        if(minYVal > maxYVal) {
171            throw new IllegalActionException(this, "minY must be less than maxY.");            
172        }
173        
174        crs.update();
175        if(_crsWasEmpty) {
176            System.err.println("Warning: No CRS supplied. Assuming EPSG:4326.");
177        }
178        
179        
180        ReferencedEnvelope envelope = new ReferencedEnvelope(minXVal, maxXVal,
181            minYVal, maxYVal, _crs);
182        output.broadcast(new BoundingBoxToken(envelope));        
183    }
184    
185    /** The maximum X value. */
186    public PortParameter maxX;
187
188    /** The maximum X value. */
189    public PortParameter maxY;
190    
191    /** The maximum X value. */
192    public PortParameter minX;
193    
194    /** The maximum X value. */
195    public PortParameter minY;
196    
197    /** The coordinate reference system. */
198    public PortParameter crs;
199    
200    /** The bounding box. */
201    public TypedIOPort output;
202    
203    /** The coordinate reference system object. */
204    private CoordinateReferenceSystem _crs;
205    
206    /** If true, crs was not set. */
207    private boolean _crsWasEmpty = false;
208}