001/* Extract an element from an array by accessing the array as a matrix. 002 003 Copyright (c) 2007-2014 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.actor.parameters.PortParameter; 031import ptolemy.data.ArrayToken; 032import ptolemy.data.BooleanToken; 033import ptolemy.data.IntToken; 034import ptolemy.data.expr.Parameter; 035import ptolemy.data.type.ArrayType; 036import ptolemy.data.type.BaseType; 037import ptolemy.kernel.CompositeEntity; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040import ptolemy.kernel.util.NameDuplicationException; 041import ptolemy.kernel.util.StringAttribute; 042import ptolemy.kernel.util.Workspace; 043 044/////////////////////////////////////////////////////////////////// 045//// ArrayElementAsMatrix 046 047/** 048 Extract an element from an array by accessing the array as a matrix. 049 050 This actor reads an array from the 051 <i>input</i> port and sends one of its elements to the <i>output</i> 052 port. The element that is extracted is determined by the 053 <i>x</i>, <i>y</i>, <i>xOffset</i> and <i>yOffset</i> parameters (or port). 054 It is required that 055 <pre> 056 0 <= <i>x</i> * <i>column</i> + <i>y</i> * <i>yOffset</i> < <i>N</i> 057 </pre> 058 where <i>N</i> is the length of the input array, or an exception will 059 be thrown by the fire() method. 060 061 @author Christopher Brooks 062 @version $Id$ 063 @since Ptolemy II 6.1 064 @Pt.ProposedRating Red (cxh) 065 @Pt.AcceptedRating Red (cxh) 066 */ 067public class ArrayElementAsMatrix extends Transformer { 068 /** Construct an actor with the given container and name. 069 * @param container The container. 070 * @param name The name of this actor. 071 * @exception IllegalActionException If the actor cannot be contained 072 * by the proposed container. 073 * @exception NameDuplicationException If the container already has an 074 * actor with this name. 075 */ 076 public ArrayElementAsMatrix(CompositeEntity container, String name) 077 throws NameDuplicationException, IllegalActionException { 078 super(container, name); 079 080 // set type constraints. 081 output.setTypeAtLeast(ArrayType.elementType(input)); 082 083 // Set parameters. 084 xOffset = new PortParameter(this, "xOffset"); 085 xOffset.setTypeEquals(BaseType.INT); 086 xOffset.setExpression("1"); 087 new Parameter(xOffset.getPort(), "_showName", BooleanToken.TRUE); 088 new StringAttribute(xOffset.getPort(), "_cardinal") 089 .setExpression("SOUTH"); 090 091 yOffset = new PortParameter(this, "yOffset"); 092 yOffset.setTypeEquals(BaseType.INT); 093 yOffset.setExpression("1"); 094 new Parameter(yOffset.getPort(), "_showName", BooleanToken.TRUE); 095 new StringAttribute(yOffset.getPort(), "_cardinal") 096 .setExpression("SOUTH"); 097 098 x = new PortParameter(this, "x"); 099 x.setTypeEquals(BaseType.INT); 100 x.setExpression("0"); 101 new Parameter(x.getPort(), "_showName", BooleanToken.TRUE); 102 new StringAttribute(x.getPort(), "_cardinal").setExpression("SOUTH"); 103 104 y = new PortParameter(this, "y"); 105 y.setTypeEquals(BaseType.INT); 106 y.setExpression("0"); 107 new Parameter(y.getPort(), "_showName", BooleanToken.TRUE); 108 new StringAttribute(y.getPort(), "_cardinal").setExpression("SOUTH"); 109 } 110 111 /////////////////////////////////////////////////////////////////// 112 //// parameters //// 113 114 /** The xOffset offset into the input array. This is an integer that 115 * defaults to 1. If the port is left unconnected, then the 116 * parameter value will be used. 117 */ 118 public PortParameter xOffset; 119 120 /** The yOffset offset into the input array. This is an integer that 121 * defaults to 1. If the port is left unconnected, then the 122 * parameter value will be used. 123 */ 124 public PortParameter yOffset; 125 126 /** The x index into the input array. This is an integer that 127 * defaults to 0. If the port is left unconnected, then the 128 * parameter value will be used. 129 */ 130 public PortParameter x; 131 132 /** The y index into the input array. This is an integer that 133 * defaults to 0. If the port is left unconnected, then the 134 * parameter value will be used. 135 */ 136 public PortParameter y; 137 138 /////////////////////////////////////////////////////////////////// 139 //// public methods //// 140 141 /** Override the base class to set type constraints. 142 * @param workspace The workspace for the new object. 143 * @return A new instance of ArrayElement. 144 * @exception CloneNotSupportedException If a derived class contains 145 * an attribute that cannot be cloned. 146 */ 147 @Override 148 public Object clone(Workspace workspace) throws CloneNotSupportedException { 149 ArrayElementAsMatrix newObject = (ArrayElementAsMatrix) super.clone( 150 workspace); 151 try { 152 newObject.output 153 .setTypeAtLeast(ArrayType.elementType(newObject.input)); 154 } catch (IllegalActionException e) { 155 // Should have been caught before. 156 throw new InternalErrorException(e); 157 } 158 return newObject; 159 } 160 161 /** Consume at most one array from the input port and produce 162 * one of its elements on the output port. If there is no token 163 * on the input, then no output is produced. 164 * @exception IllegalActionException If the <i>index</i> parameter 165 * (or port value) is out of range. 166 */ 167 @Override 168 public void fire() throws IllegalActionException { 169 super.fire(); 170 // NOTE: This has be outside the if because we need to ensure 171 // that if an index token is provided that it is consumed even 172 // if there is no input token. 173 xOffset.update(); 174 yOffset.update(); 175 x.update(); 176 y.update(); 177 178 int xOffsetValue = ((IntToken) xOffset.getToken()).intValue(); 179 int yOffsetValue = ((IntToken) yOffset.getToken()).intValue(); 180 int xValue = ((IntToken) x.getToken()).intValue(); 181 int yValue = ((IntToken) y.getToken()).intValue(); 182 183 if (input.hasToken(0)) { 184 ArrayToken token = (ArrayToken) input.get(0); 185 186 if (xOffsetValue < 0 || yOffsetValue < 0 || xValue < 0 || yValue < 0 187 || xValue * xOffsetValue + yValue * yOffsetValue >= token 188 .length()) { 189 throw new IllegalActionException(this, 190 "xValue (" + xValue + ") * xOffsetValue *(" 191 + xOffsetValue + " ) + yValue (" + yValue 192 + ") * yOffsetValue (" + yOffsetValue + ") = " 193 + xValue * xOffsetValue + yValue * yOffsetValue 194 + " is less than zero or otherwise " 195 + "out of range for the input " 196 + "array, which has length " + token.length()); 197 } 198 199 output.send(0, token 200 .getElement(xValue * xOffsetValue + yValue * yOffsetValue)); 201 } 202 } 203}