001/* An actor that outputs a specified trigonometric function of the input. 002 003 Copyright (c) 1998-2016 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.actor.lib; 029 030import ptolemy.data.DoubleToken; 031import ptolemy.data.ScalarToken; 032import ptolemy.data.Token; 033import ptolemy.data.expr.StringParameter; 034import ptolemy.data.type.BaseType; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.InternalErrorException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.Workspace; 041 042// NOTE: If you update the list of functions, then you will want 043// to update the list in actor/lib/math.xml. 044/////////////////////////////////////////////////////////////////// 045//// TrigFunction 046 047/** 048 <p>Produce an output token on each firing with a value that is 049 equal to the specified trigonometric function of the input. 050 The input and output types are DoubleToken. The functions 051 are exactly those in the java.lang.Math class. They are:</p> 052 <ul> 053 <li> <b>acos</b>: The arc cosine of an angle. The returned value 054 is between 0.0 an pi. 055 If the absolute value of the argument is greater than one or if the 056 argument is NaN, then the returned value is NaN. 057 </li> 058 <li> <b>asin</b>: The arc sine of an angle. The returned value 059 is between -pi/2 through pi/2. 060 If the absolute value of the argument is greater than one or if the 061 argument is NaN, then the returned value is NaN. 062 If the argument is positive zero, then the returned value is positive 063 zero. 064 If the argument is negative zero, then the returned value is negative 065 zero. 066 </li> 067 <li> <b>atan</b>: The arc tangent of an angle. The returned value is 068 between -pi/2 through pi/2. 069 If the argument is NaN, then the returned value is NaN. 070 If the argument is positive zero, then the returned value is positive 071 zero. 072 If the argument is negative zero, then the returned value is negative 073 zero. 074 </li> 075 <li> <b>cos</b>: The trigonometric cosine of an angle. 076 If the argument is an infinity or NaN, then the returned value is NaN. 077 </li> 078 <li> <b>sin</b>: The trigonometric sine of an angle. 079 If the argument is an infinity or NaN, then the returned value is NaN. 080 </li> 081 <li> <b>tan</b>: The trigonometric tangent of an angle. 082 If the argument is an infinity or NaN, then the returned value is NaN. 083 If the argument is positive zero, then the returned value is positive 084 zero. 085 If the argument is negative zero, then the returned value is negative 086 zero. 087 </li> 088 </ul> 089 <p> The following functions in java.lang.Math are implemented elsewhere:</p> 090 <ul> 091 <li> <b>abs</b>: AbsoluteValue actor. 092 </li><li> <b>atan2</b>: CartesianToPolar actor. 093 </li><li> <b>ceil</b>: Round actor 094 </li><li> <b>exp</b>: MathFunction actor. 095 </li><li> <b>floor</b>: Round actor 096 </li><li> <b>remainder</b>: MathFunction actor. 097 </li><li> <b>log</b>: MathFunction actor. 098 </li><li> <b>max</b>: Maximum actor. 099 </li><li> <b>min</b>: Minimum actor. 100 </li><li> <b>round</b>: Round actor. 101 </li><li> <b>sqrt</b>: MathFunction actor. 102 </li><li> <b>toDegrees</b>: Scale actor (with factor 180.0/PI). 103 </li><li> <b>toRadians</b>: Scale actor (with factor PI/180.0). 104 </li></ul> 105 106 @author Edward A. Lee 107 @version $Id$ 108 @since Ptolemy II 1.0 109 @Pt.ProposedRating Yellow (eal) 110 @Pt.AcceptedRating Yellow (pwhitake) 111 @see ptolemy.actor.lib.conversions.CartesianToPolar 112 @see AbsoluteValue 113 @see UnaryMathFunction 114 @see Scale 115 */ 116public class TrigFunction extends Transformer { 117 /** Construct an actor with the given container and name. 118 * @param container The container. 119 * @param name The name of this actor. 120 * @exception IllegalActionException If the actor cannot be contained 121 * by the proposed container. 122 * @exception NameDuplicationException If the container already has an 123 * actor with this name. 124 */ 125 public TrigFunction(CompositeEntity container, String name) 126 throws NameDuplicationException, IllegalActionException { 127 super(container, name); 128 129 // parameters 130 function = new StringParameter(this, "function"); 131 function.setExpression("sin"); 132 function.addChoice("acos"); 133 function.addChoice("asin"); 134 function.addChoice("atan"); 135 function.addChoice("cos"); 136 function.addChoice("sin"); 137 function.addChoice("tan"); 138 139 _function = _SIN; 140 141 input.setTypeEquals(BaseType.DOUBLE); 142 output.setTypeEquals(BaseType.DOUBLE); 143 144 _attachText("_iconDescription", 145 "<svg>\n" + "<rect x=\"-30\" y=\"-15\" " 146 + "width=\"60\" height=\"30\" " 147 + "style=\"fill:white\"/>\n" + "</svg>\n"); 148 } 149 150 /////////////////////////////////////////////////////////////////// 151 //// ports and parameters //// 152 153 /** The function to compute. This is a string-valued attribute 154 * that defaults to "sin". 155 */ 156 public StringParameter function; 157 158 /////////////////////////////////////////////////////////////////// 159 //// public methods //// 160 161 /** Override the base class to determine which function is being 162 * specified. 163 * @param attribute The attribute that changed. 164 * @exception IllegalActionException If the function is not recognized. 165 */ 166 @Override 167 public void attributeChanged(Attribute attribute) 168 throws IllegalActionException { 169 if (attribute == function) { 170 String functionName = function.stringValue(); 171 172 if (functionName.equals("acos")) { 173 _function = _ACOS; 174 } else if (functionName.equals("asin")) { 175 _function = _ASIN; 176 } else if (functionName.equals("atan")) { 177 _function = _ATAN; 178 } else if (functionName.equals("cos")) { 179 _function = _COS; 180 } else if (functionName.equals("sin")) { 181 _function = _SIN; 182 } else if (functionName.equals("tan")) { 183 _function = _TAN; 184 } else { 185 throw new IllegalActionException(this, 186 "Unrecognized trigonometric function: " + functionName); 187 } 188 } else { 189 super.attributeChanged(attribute); 190 } 191 } 192 193 /** Clone the actor into the specified workspace. 194 * @param workspace The workspace for the new object. 195 * @return A new actor. 196 * @exception CloneNotSupportedException If a derived class contains 197 * an attribute that cannot be cloned. 198 */ 199 @Override 200 public Object clone(Workspace workspace) throws CloneNotSupportedException { 201 TrigFunction newObject = (TrigFunction) super.clone(workspace); 202 203 newObject._resultArray = new DoubleToken[1]; 204 205 return newObject; 206 } 207 208 /** Compute the specified trigonometric function of the input. 209 * If there is no input, then produce no output. 210 * @exception IllegalActionException If there is no director. 211 */ 212 @Override 213 public void fire() throws IllegalActionException { 214 super.fire(); 215 if (input.hasToken(0)) { 216 double in = ((ScalarToken) input.get(0)).doubleValue(); 217 output.send(0, new DoubleToken(_doFunction(in))); 218 } 219 } 220 221 /** Invoke a specified number of iterations of this actor. Each 222 * iteration computes the trigonometric function specified by the 223 * <i>function</i> attribute on a single token. An invocation 224 * of this method therefore applies the function to <i>count</i> 225 * successive input tokens. 226 * <p> 227 * This method should be called instead of the usual prefire(), 228 * fire(), postfire() methods when this actor is used in a 229 * domain that supports vectorized actors. This leads to more 230 * efficient execution. 231 * @param count The number of iterations to perform. 232 * @return COMPLETED if the actor was successfully iterated the 233 * specified number of times. Otherwise, return NOT_READY, and do 234 * not consume any input tokens. 235 * @exception IllegalActionException If iterating cannot be 236 * performed. 237 */ 238 @Override 239 public int iterate(int count) throws IllegalActionException { 240 // Check whether we need to reallocate the output token array. 241 if (count > _resultArray.length) { 242 _resultArray = new DoubleToken[count]; 243 } 244 245 if (input.hasToken(0, count)) { 246 // NOTE: inArray.length may be > count, in which case 247 // only the first count tokens are valid. 248 Token[] inArray = input.get(0, count); 249 250 for (int i = 0; i < count; i++) { 251 double inputValue = ((ScalarToken) inArray[i]).doubleValue(); 252 _resultArray[i] = new DoubleToken(_doFunction(inputValue)); 253 } 254 255 output.send(0, _resultArray, count); 256 return COMPLETED; 257 } else { 258 return NOT_READY; 259 } 260 } 261 262 /////////////////////////////////////////////////////////////////// 263 //// private methods //// 264 265 /** Calculate the function on the given argument. 266 * @param in The input value. 267 * @return The result of applying the function. 268 */ 269 private double _doFunction(double in) { 270 double result; 271 272 switch (_function) { 273 case _ACOS: 274 result = Math.acos(in); 275 break; 276 277 case _ASIN: 278 result = Math.asin(in); 279 break; 280 281 case _ATAN: 282 result = Math.atan(in); 283 break; 284 285 case _COS: 286 result = Math.cos(in); 287 break; 288 289 case _SIN: 290 result = Math.sin(in); 291 break; 292 293 case _TAN: 294 result = Math.tan(in); 295 break; 296 297 default: 298 throw new InternalErrorException( 299 "Invalid value for _function private variable. " 300 + "TrigFunction actor (" + getFullName() + ")" 301 + " on function type " + _function); 302 } 303 304 return result; 305 } 306 307 /////////////////////////////////////////////////////////////////// 308 //// private variables //// 309 private DoubleToken[] _resultArray = new DoubleToken[1]; 310 311 // An indicator for the function to compute. 312 private int _function; 313 314 // Constants used for more efficient execution. 315 private static final int _ACOS = 0; 316 317 private static final int _ASIN = 1; 318 319 private static final int _ATAN = 2; 320 321 private static final int _COS = 3; 322 323 private static final int _SIN = 4; 324 325 private static final int _TAN = 5; 326}