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}