001/* 002 * Copyright (c) 2014-2015 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-12-17 19:34:32 +0000 (Thu, 17 Dec 2015) $' 007 * '$Revision: 34347 $' 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; 030 031import java.util.ArrayList; 032import java.util.List; 033 034import ptolemy.actor.TypedAtomicActor; 035import ptolemy.actor.TypedIOPort; 036import ptolemy.actor.parameters.PortParameter; 037import ptolemy.data.ArrayToken; 038import ptolemy.data.BooleanToken; 039import ptolemy.data.DoubleToken; 040import ptolemy.data.RecordToken; 041import ptolemy.data.StringToken; 042import ptolemy.data.Token; 043import ptolemy.data.expr.Parameter; 044import ptolemy.data.type.ArrayType; 045import ptolemy.data.type.BaseType; 046import ptolemy.data.type.RecordType; 047import ptolemy.data.type.Type; 048import ptolemy.kernel.CompositeEntity; 049import ptolemy.kernel.util.Attribute; 050import ptolemy.kernel.util.IllegalActionException; 051import ptolemy.kernel.util.NameDuplicationException; 052import ptolemy.kernel.util.SingletonAttribute; 053 054/** An actor that covers a bounding box with non-overlapping 055 * regions each whose side is less than a maximum length. 056 * 057 * @deprecated Use CoverBoundingBox instead. 058 * @see org.kepler.gis.actor.bbox.CoverBoundingBox 059 * 060 * @author Daniel Crawl 061 * @version $Id: SplitBoundingBox.java 34347 2015-12-17 19:34:32Z crawl $ 062 */ 063public class SplitBoundingBox extends TypedAtomicActor { 064 065 public SplitBoundingBox(CompositeEntity container, String name) 066 throws IllegalActionException, NameDuplicationException { 067 super(container, name); 068 069 top = new PortParameter(this, "top"); 070 top.setTypeEquals(BaseType.DOUBLE); 071 new SingletonAttribute(top.getPort(), "_showName"); 072 073 bottom = new PortParameter(this, "bottom"); 074 bottom.setTypeEquals(BaseType.DOUBLE); 075 new SingletonAttribute(bottom.getPort(), "_showName"); 076 077 left = new PortParameter(this, "left"); 078 left.setTypeEquals(BaseType.DOUBLE); 079 new SingletonAttribute(left.getPort(), "_showName"); 080 081 right = new PortParameter(this, "right"); 082 right.setTypeEquals(BaseType.DOUBLE); 083 new SingletonAttribute(right.getPort(), "_showName"); 084 085 maxLength = new PortParameter(this, "maxLength"); 086 maxLength.setTypeEquals(BaseType.DOUBLE); 087 new SingletonAttribute(maxLength.getPort(), "_showName"); 088 089 regions = new TypedIOPort(this, "regions", false, true); 090 091 labelEachRegion = new Parameter(this, "labelEachRegion"); 092 labelEachRegion.setTypeEquals(BaseType.BOOLEAN); 093 labelEachRegion.setToken(BooleanToken.TRUE); 094 } 095 096 @Override 097 public void attributeChanged(Attribute attribute) throws IllegalActionException { 098 099 if(attribute == labelEachRegion) { 100 _labelEachRegion = ((BooleanToken)labelEachRegion.getToken()).booleanValue(); 101 if(_labelEachRegion) { 102 regions.setTypeEquals(_outputTypeWithID); 103 } else { 104 regions.setTypeEquals(_outputType); 105 } 106 } else { 107 super.attributeChanged(attribute); 108 } 109 } 110 111 /* 112 @Override 113 public Object clone(Workspace workspace) throws CloneNotSupportedException { 114 SplitBoundingBox newObject = (SplitBoundingBox) super.clone(workspace); 115 newObject._regionPrefix = _regionPrefix; 116 return newObject; 117 } 118 */ 119 120 @Override 121 public void fire() throws IllegalActionException { 122 123 top.update(); 124 bottom.update(); 125 left.update(); 126 right.update(); 127 maxLength.update(); 128 129 final double topValue = _readValue(top); 130 final double bottomValue = _readValue(bottom); 131 final double leftValue = _readValue(left); 132 final double rightValue = _readValue(right); 133 134 // perform sanity checks 135 if(topValue <= bottomValue) { 136 throw new IllegalActionException(this, 137 "Top is less than or equal to the bottom coordinates."); 138 } 139 140 if(rightValue <= leftValue) { 141 throw new IllegalActionException(this, 142 "Right is smaller than or equal to the left coordinates."); 143 } 144 145 final double maxLengthValue = _readValue(maxLength); 146 147 if(maxLengthValue <= 0) { 148 throw new IllegalActionException(this, 149 "Maximum length must be greater than 0."); 150 } 151 152 // determine height 153 final double height = topValue - bottomValue; 154 final double numRegionsHeight = Math.ceil(height / maxLengthValue); 155 final double regionHeightLength = height / numRegionsHeight; 156 //System.out.println("# regions h = " + regionsHeightLength + ", length = " + regionsHeightLength); 157 158 // determine width 159 final double width = rightValue - leftValue; 160 final double numRegionsWidth = Math.ceil(width / maxLengthValue); 161 final double regionWidthLength = width / numRegionsWidth; 162 //System.out.println("# regions w = " + numRegionsWidth + ", length = " + regionsWidthLength); 163 164 List<RecordToken> tokens = new ArrayList<RecordToken>(); 165 int curID = 0; 166 for(int x = 1; x <= numRegionsWidth; x++) { 167 for(int y = 1; y <= numRegionsHeight; y++) { 168 DoubleToken curTop = 169 new DoubleToken(bottomValue + y*regionHeightLength); 170 DoubleToken curBottom = 171 new DoubleToken(curTop.doubleValue() - regionHeightLength); 172 DoubleToken curRight = 173 new DoubleToken(leftValue + x*regionWidthLength); 174 DoubleToken curLeft = 175 new DoubleToken(curRight.doubleValue() - regionWidthLength); 176 RecordToken record = null; 177 if(_labelEachRegion) { 178 record = new RecordToken(_recordNamesWithID, 179 new Token[] {curTop, curBottom, curRight, curLeft, 180 new StringToken(_regionPrefix + curID)}); 181 curID++; 182 } else { 183 record = new RecordToken(_recordNames, 184 new Token[] {curTop, curBottom, curRight, curLeft}); 185 } 186 187 tokens.add(record); 188 189 //System.out.println(curTop + " " + curBottom + " " + curRight + " " + curLeft); 190 } 191 } 192 193 regions.broadcast(new ArrayToken(tokens.toArray(new Token[tokens.size()]))); 194 195 } 196 197 private double _readValue(PortParameter pp) throws IllegalActionException { 198 Token token = pp.getToken(); 199 if(token == null) { 200 throw new IllegalActionException(this, 201 "Missing value for " + pp.getName()); 202 } 203 return ((DoubleToken)token).doubleValue(); 204 } 205 206 /** The latitude of the top of the bounding box. */ 207 public PortParameter top; 208 209 /** The latitude of the bottom of the bounding box. */ 210 public PortParameter bottom; 211 212 /** The longitude of the left of the bounding box. */ 213 public PortParameter left; 214 215 /** The longitude of the right of the bounding box. */ 216 public PortParameter right; 217 218 /** The maximum length of any side of a region within the bounding box. */ 219 public PortParameter maxLength; 220 221 /** If true, each region is given a unique label. */ 222 public Parameter labelEachRegion; 223 224 /** The non-overlapping regions that cover the bounding box. */ 225 public TypedIOPort regions; 226 227 private final static String[] _recordNames = 228 new String[] {"top", "bottom", "right", "left"}; 229 private final static String[] _recordNamesWithID = 230 new String[] {"top", "bottom", "right", "left", "id"}; 231 232 private final static Type _outputType = 233 new ArrayType(new RecordType(_recordNames, 234 new Type[] { 235 BaseType.DOUBLE, 236 BaseType.DOUBLE, 237 BaseType.DOUBLE, 238 BaseType.DOUBLE})); 239 240 private final static Type _outputTypeWithID = 241 new ArrayType(new RecordType(_recordNamesWithID, 242 new Type[] { 243 BaseType.DOUBLE, 244 BaseType.DOUBLE, 245 BaseType.DOUBLE, 246 BaseType.DOUBLE, 247 BaseType.STRING})); 248 249 private boolean _labelEachRegion = true; 250 251 // TODO either make final static or changeable via a parameter. 252 private String _regionPrefix = "region"; 253}