001/* Plot XY functions. 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.actor.TypedIOPort; 031import ptolemy.data.DoubleToken; 032import ptolemy.data.IntToken; 033import ptolemy.data.type.BaseType; 034import ptolemy.kernel.CompositeEntity; 035import ptolemy.kernel.util.IllegalActionException; 036import ptolemy.kernel.util.NameDuplicationException; 037import ptolemy.plot.Plot; 038 039/////////////////////////////////////////////////////////////////// 040//// XYPlotter 041 042/** 043 An XY plotter. This plotter contains an instance of the Plot class 044 from the Ptolemy plot package as a public member. 045 Data at <i>inputX</i> and <i>inputY</i> are plotted on this instance. 046 Both <i>inputX</i> and <i>inputY</i> are multiports with type DOUBLE. 047 When plotted, the first channel of <i>inputX</i> and the first channel 048 of <i>inputY</i> are together considered the first signal, 049 then the second channel of <i>inputX</i> and the second channel 050 of <i>inputY</i> are considered the second signal, and so on. 051 This requires that <i>inputX</i> and 052 <i>inputY</i> have the same width. The actor 053 assumes that there is at least one token available on each channel 054 when it fires. The horizontal axis is given by the value of the 055 input from <i>inputX</i> and vertical axis is given by <i>inputY</i>. 056 057 @author Jie Liu 058 @version $Id$ 059 @since Ptolemy II 1.0 060 @Pt.ProposedRating Green (liuj) 061 @Pt.AcceptedRating Green (cxh) 062 */ 063public class XYPlotter extends Plotter { 064 /** Construct an actor with the given container and name. 065 * @param container The container. 066 * @param name The name of this actor. 067 * @exception IllegalActionException If the actor cannot be contained 068 * by the proposed container. 069 * @exception NameDuplicationException If the container already has an 070 * actor with this name. 071 */ 072 public XYPlotter(CompositeEntity container, String name) 073 throws IllegalActionException, NameDuplicationException { 074 super(container, name); 075 076 // Create the input ports and make them single ports. 077 inputX = new TypedIOPort(this, "inputX", true, false); 078 inputX.setMultiport(true); 079 inputX.setTypeEquals(BaseType.DOUBLE); 080 081 inputY = new TypedIOPort(this, "inputY", true, false); 082 inputY.setMultiport(true); 083 inputY.setTypeEquals(BaseType.DOUBLE); 084 085 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-20\" y=\"-20\" " 086 + "width=\"40\" height=\"40\" " + "style=\"fill:lightGrey\"/>\n" 087 + "<rect x=\"-12\" y=\"-12\" " + "width=\"24\" height=\"24\" " 088 + "style=\"fill:white\"/>\n" + "<rect x=\"2\" y=\"-18\" " 089 + "width=\"4\" height=\"4\" " + "style=\"fill:grey\"/>\n" 090 + "<rect x=\"8\" y=\"-18\" " + "width=\"4\" height=\"4\" " 091 + "style=\"fill:grey\"/>\n" + "<rect x=\"14\" y=\"-18\" " 092 + "width=\"4\" height=\"4\" " + "style=\"fill:grey\"/>\n" 093 + "<ellipse cx=\"-4\" cy=\"0\" " + "rx=\"4\" ry=\"8\" " 094 + "style=\"stroke:red\"/>\n" + "<ellipse cx=\"4\" cy=\"0\" " 095 + "rx=\"4\" ry=\"8\" " + "style=\"stroke:red\"/>\n" 096 + "</svg>\n"); 097 } 098 099 /////////////////////////////////////////////////////////////////// 100 //// ports and parameters //// 101 102 /** Input port for the horizontal axis, with type DOUBLE. */ 103 public TypedIOPort inputX; 104 105 /** Input port for the vertical axis, with type DOUBLE. */ 106 public TypedIOPort inputY; 107 108 /////////////////////////////////////////////////////////////////// 109 //// public methods //// 110 111 /** Read at most one token from each channel of each input port 112 * and plot it. 113 * This is done in postfire to ensure that data has settled. 114 * The width of the inputs should be the same, otherwise a 115 * exception will be thrown. The channels from the two input 116 * ports are matched to give the X and Y position of a single 117 * data point. Each matched channel pair must have 118 * at least one token, or 119 * a token will be consumed from the input channel that has 120 * a token, but nothing will be plotted. 121 * @exception IllegalActionException If there is no director, 122 * the width of the ports are not the same, or 123 * if the base class throws it. 124 * @return True if it is OK to continue. 125 */ 126 @Override 127 public boolean postfire() throws IllegalActionException { 128 int widthX = inputX.getWidth(); 129 int widthY = inputY.getWidth(); 130 131 if (widthX != widthY) { 132 throw new IllegalActionException(this, 133 " The number of input channels mismatch."); 134 } 135 136 int offset = ((IntToken) startingDataset.getToken()).intValue(); 137 138 for (int i = widthX - 1; i >= 0; i--) { 139 boolean hasX = false; 140 boolean hasY = false; 141 double xValue = 0.0; 142 double yValue = 0.0; 143 144 if (inputX.hasToken(i)) { 145 xValue = ((DoubleToken) inputX.get(i)).doubleValue(); 146 hasX = true; 147 } 148 149 if (inputY.hasToken(i)) { 150 yValue = ((DoubleToken) inputY.get(i)).doubleValue(); 151 hasY = true; 152 } 153 154 if (hasX && hasY) { 155 // NOTE: We assume the superclass ensures this cast is safe. 156 ((Plot) plot).addPoint(i + offset, xValue, yValue, true); 157 } 158 } 159 160 return super.postfire(); 161 } 162}