001/* Plot X-Y data with finite persistence.
002
003 @Copyright (c) 1998-2014 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the
009 above copyright notice and the following two paragraphs appear in all
010 copies of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION 2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.lib.gui;
029
030import ptolemy.data.IntToken;
031import ptolemy.data.expr.Parameter;
032import ptolemy.data.type.BaseType;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.Attribute;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.NameDuplicationException;
037import ptolemy.plot.Plot;
038
039///////////////////////////////////////////////////////////////////
040//// XYScope
041
042/**
043 <p>An X-Y plotter that plots with finite persistence.
044 This plotter contains an instance of the Plot class
045 from the Ptolemy plot package as a public member.
046 Data at <i>inputX</i> and <i>inputY</i> are plotted on this instance.
047 Both <i>inputX</i> and <i>inputY</i> are multiports that
048 take a DoubleToken.
049 When plotted, the first channel of <i>inputX</i> and the first channel
050 of <i>inputY</i> are together considered the first signal,
051 then the second channel of <i>inputX</i> and the second channel
052 of <i>inputY</i> are considered the second signal, and so on.
053 This requires that <i>inputX</i> and
054 <i>inputY</i> have the same width.
055 </p><p>
056 This actor
057 assumes that there is at least one token available on each channel
058 when it fires. The horizontal axis is given by the value of the
059 input from <i>inputX</i> and vertical axis is given by <i>inputY</i>.
060 </p><p>
061 If the <i>persistence</i> parameter is positive, then it specifies
062 the number of points that are shown.
063 It defaults to 100, so any point older than 100 samples is
064 erased and forgotten.</p>
065
066 @author  Edward A. Lee
067 @version $Id$
068 @since Ptolemy II 1.0
069 @Pt.ProposedRating Yellow (eal)
070 @Pt.AcceptedRating Yellow (neuendor)
071 */
072public class XYScope extends XYPlotter {
073    /** Construct an actor with the given container and name.
074     *  @param container The container.
075     *  @param name The name of this actor.
076     *  @exception IllegalActionException If the actor cannot be contained
077     *   by the proposed container.
078     *  @exception NameDuplicationException If the container already has an
079     *   actor with this name.
080     */
081    public XYScope(CompositeEntity container, String name)
082            throws IllegalActionException, NameDuplicationException {
083        super(container, name);
084
085        // set the parameters
086        persistence = new Parameter(this, "persistence", new IntToken(100));
087        persistence.setTypeEquals(BaseType.INT);
088    }
089
090    ///////////////////////////////////////////////////////////////////
091    ////                     ports and parameters                  ////
092
093    /** The number of samples from each input channel
094     *  displayed at any one time (an integer).
095     */
096    public Parameter persistence;
097
098    ///////////////////////////////////////////////////////////////////
099    ////                         public methods                    ////
100
101    /** Notify this that an attribute has changed.  If either parameter
102     *  is changed, then this actor updates the configuration of the
103     *  visible plot.
104     *  @param attribute The attribute that changed.
105     *  @exception IllegalActionException If the expression of the
106     *  attribute cannot be parsed or cannot be evaluated.
107     */
108    @Override
109    public void attributeChanged(Attribute attribute)
110            throws IllegalActionException {
111        if (attribute == persistence && plot != null) {
112            int persValue = ((IntToken) persistence.getToken()).intValue();
113
114            // NOTE: We assume the superclass ensures this cast is safe.
115            ((Plot) plot).setPointsPersistence(persValue);
116        } else {
117            super.attributeChanged(attribute);
118        }
119    }
120
121    /** Configure the plotter using the current parameter values.
122     *  @exception IllegalActionException If the parent class throws it.
123     */
124    @Override
125    public void initialize() throws IllegalActionException {
126        super.initialize();
127
128        int persValue = ((IntToken) persistence.getToken()).intValue();
129
130        // NOTE: We assume the superclass ensures this cast is safe.
131        ((Plot) plot).setPointsPersistence(persValue);
132        plot.repaint();
133
134        // Override the default so that there are not gaps in the lines.
135        if (((Plot) plot).getMarksStyle().equals("none")) {
136            ((Plot) plot).setMarksStyle("pixels");
137        }
138    }
139
140    /** Call the base class postfire() method, then yield this
141     *  thread so that the event thread gets a chance.  This is necessary,
142     *  because otherwise the swing thread may be starved and accumulate a
143     *  large number of points waiting to be plotted.
144     *  @exception IllegalActionException If there is no director,
145     *  or if the base class throws it.
146     *  @return True if it is OK to continue.
147     */
148    @Override
149    public boolean postfire() throws IllegalActionException {
150        boolean result = super.postfire();
151        plot.repaint();
152        Thread.yield();
153        return result;
154    }
155}