001/* Plot functions of time. 002 003 @Copyright (c) 1998-2018 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 java.util.ArrayList; 031 032import ptolemy.actor.TimedActor; 033import ptolemy.actor.TypedIOPort; 034import ptolemy.data.BooleanToken; 035import ptolemy.data.DoubleToken; 036import ptolemy.data.IntToken; 037import ptolemy.data.SmoothToken; 038import ptolemy.data.expr.Parameter; 039import ptolemy.data.type.BaseType; 040import ptolemy.kernel.CompositeEntity; 041import ptolemy.kernel.util.IllegalActionException; 042import ptolemy.kernel.util.NameDuplicationException; 043import ptolemy.kernel.util.Workspace; 044import ptolemy.plot.PlotInterface; 045 046/////////////////////////////////////////////////////////////////// 047//// TimedPlotter 048 049/** 050 A signal plotter. This plotter contains an instance of the Plot class 051 from the Ptolemy plot package as a public member. Data at the input, which 052 can consist of any number of channels, are plotted on this instance. 053 Each channel is plotted as a separate data set. 054 The horizontal axis represents time, which by default is the global 055 time of the model (the model time of the top-level director). 056 Setting <i>useLocalTime</i> to true changes this to use the 057 local time of the input port, which is (in most domains) the model 058 time of the local director. 059 060 @author Edward A. Lee, Contributor: Bert Rodiers 061 @version $Id$ 062 @since Ptolemy II 1.0 063 @Pt.ProposedRating Green (eal) 064 @Pt.AcceptedRating Green (cxh) 065 */ 066public class TimedPlotter extends Plotter implements TimedActor { 067 /** Construct an actor with the given container and name. 068 * @param container The container. 069 * @param name The name of this actor. 070 * @exception IllegalActionException If the actor cannot be contained 071 * by the proposed container. 072 * @exception NameDuplicationException If the container already has an 073 * actor with this name. 074 */ 075 public TimedPlotter(CompositeEntity container, String name) 076 throws IllegalActionException, NameDuplicationException { 077 super(container, name); 078 disconnectGraphOnAbsentValue = new Parameter(this, 079 "disconnectGraphOnAbsentValue", new BooleanToken(false)); 080 disconnectGraphOnAbsentValue.setTypeEquals(BaseType.BOOLEAN); 081 082 // Create the input port and make it a multiport. 083 input = new TypedIOPort(this, "input", true, false); 084 input.setMultiport(true); 085 input.setTypeEquals(BaseType.DOUBLE); 086 087 useLocalTime = new Parameter(this, "useLocalTime"); 088 useLocalTime.setTypeEquals(BaseType.BOOLEAN); 089 useLocalTime.setExpression("false"); 090 } 091 092 /////////////////////////////////////////////////////////////////// 093 //// ports and parameters //// 094 095 /** When disconnectGraphOnAbsentValue is True there will be a gap 096 * in the graph each time a the actor is fired, but the value 097 * is absent for a certain channel. Especially in the continuous 098 * domain this options is useful. By default this parameter is 099 * False. 100 */ 101 public Parameter disconnectGraphOnAbsentValue; 102 103 /** Input port, which has type DoubleToken. */ 104 public TypedIOPort input; 105 106 /** If true, use the model time reported by the input port, 107 * which is normally the model time of the local director. 108 * If false (the default), use the model time reported by 109 * the top-level director. Local time may differ 110 * from global time inside modal models and certain domains 111 * that manipulate time. 112 */ 113 public Parameter useLocalTime; 114 115 /////////////////////////////////////////////////////////////////// 116 //// public methods //// 117 118 /** Clone the actor into the specified workspace. This calls the 119 * base class and then creates new ports and parameters. 120 * @param workspace The workspace for the new object. 121 * @return A new actor. 122 * @exception CloneNotSupportedException If a derived class has an 123 * attribute that cannot be cloned. 124 */ 125 @Override 126 public Object clone(Workspace workspace) throws CloneNotSupportedException { 127 TimedPlotter newObject = (TimedPlotter) super.clone(workspace); 128 newObject._connected = new ArrayList<Boolean>(); 129 return newObject; 130 } 131 132 /** Pre-fire this actor. Recompute _connected is needed 133 * @exception IllegalActionException If a derived class throws it. 134 */ 135 @Override 136 public boolean prefire() throws IllegalActionException { 137 super.prefire(); 138 139 int width = input.getWidth(); 140 if (width != _connected.size()) { 141 _connected.clear(); 142 for (int i = 0; i < width; i++) { 143 _connected.add(true); 144 } 145 } 146 return true; 147 } 148 149 /** Initialize this actor. Derived classes override this method 150 * to perform actions that should occur once at the beginning of 151 * an execution, but after type resolution. Derived classes can 152 * produce output data and schedule events. 153 * 154 * @exception IllegalActionException If a derived class throws it. 155 */ 156 @Override 157 public void initialize() throws IllegalActionException { 158 super.initialize(); 159 int width = input.getWidth(); 160 _connected.clear(); 161 for (int i = 0; i < width; i++) { 162 _connected.add(true); 163 } 164 ((PlotInterface) plot).markDisconnections(true); 165 } 166 167 /** Read at most one input from each channel and plot it as a 168 * function of time. 169 * This is done in postfire to ensure that data has settled. 170 * @exception IllegalActionException If there is no director, or 171 * if the base class throws it. 172 * @return True if it is OK to continue. 173 */ 174 @Override 175 public boolean postfire() throws IllegalActionException { 176 double currentTimeValue; 177 int width = input.getWidth(); 178 179 boolean disconnectOnAbsent = ((BooleanToken) disconnectGraphOnAbsentValue 180 .getToken()).booleanValue(); 181 int offset = ((IntToken) startingDataset.getToken()).intValue(); 182 183 // NOTE: We assume the superclass ensures this cast is safe. 184 PlotInterface plot = (PlotInterface) this.plot; 185 for (int i = width - 1; i >= 0; i--) { 186 if (input.hasToken(i)) { 187 boolean localTime = ((BooleanToken) useLocalTime.getToken()) 188 .booleanValue(); 189 if (localTime) { 190 currentTimeValue = input.getModelTime(i).getDoubleValue(); 191 } else { 192 currentTimeValue = getDirector().getGlobalTime() 193 .getDoubleValue(); 194 } 195 196 DoubleToken currentToken = (DoubleToken) input.get(i); 197 SmoothToken smoothToken = currentToken instanceof SmoothToken 198 ? (SmoothToken) currentToken 199 : null; 200 double[] derivatives; 201 if (smoothToken != null) { 202 derivatives = smoothToken.derivativeValues(); 203 if (derivatives == null) { 204 derivatives = new double[0]; 205 } 206 } else { 207 derivatives = null; 208 } 209 plot.addPoint(i + offset, currentTimeValue, 210 currentToken.doubleValue(), derivatives, 211 _connected.get(i)); 212 if (disconnectOnAbsent) { 213 _connected.set(i, true); 214 } 215 } else if (disconnectOnAbsent) { 216 // We have not token, and hence we want to create a gap 217 // in the graph. 218 _connected.set(i, false); 219 } 220 } 221 222 return super.postfire(); 223 } 224 225 /////////////////////////////////////////////////////////////////// 226 //// private variables //// 227 228 private ArrayList<Boolean> _connected = new ArrayList<Boolean>(); 229}