001/* 002 * Copyright (c) 2002-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-08-24 22:48:48 +0000 (Mon, 24 Aug 2015) $' 007 * '$Revision: 33634 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.geon; 031 032import java.io.File; 033import java.io.FileInputStream; 034import java.io.InputStream; 035import java.util.Set; 036import java.util.Vector; 037 038import javax.xml.parsers.DocumentBuilder; 039import javax.xml.parsers.DocumentBuilderFactory; 040 041import org.w3c.dom.Document; 042import org.w3c.dom.Element; 043import org.w3c.dom.NodeList; 044 045import nl.skybound.awt.DoublePolygon; 046import ptolemy.actor.lib.Source; 047import ptolemy.data.DoubleToken; 048import ptolemy.data.ObjectToken; 049import ptolemy.data.StringToken; 050import ptolemy.data.Token; 051import ptolemy.data.expr.ASTPtRootNode; 052import ptolemy.data.expr.FileParameter; 053import ptolemy.data.expr.ModelScope; 054import ptolemy.data.expr.ParseTreeEvaluator; 055import ptolemy.data.expr.PtParser; 056import ptolemy.data.type.BaseType; 057import ptolemy.data.type.Type; 058import ptolemy.data.type.TypeConstant; 059import ptolemy.kernel.CompositeEntity; 060import ptolemy.kernel.util.IllegalActionException; 061import ptolemy.kernel.util.NameDuplicationException; 062 063////////////////////////////////////////////////////////////////////////// 064//// SVGToPolygon 065/** 066 * This actor converts an SVG file into polygon objects. The polygon coordinates 067 * are read using the polygon tag. 068 * 069 * @author Efrat Jaeger 070 * @version $Id: SVGToPolygon.java 33634 2015-08-24 22:48:48Z crawl $ 071 * @since Ptolemy II 3.0.2 072 */ 073public class SVGToPolygon extends Source { 074 075 /** 076 * Construct an actor with the given container and name. 077 * 078 * @param container 079 * The container. 080 * @param name 081 * The name of this actor. 082 * @exception IllegalActionException 083 * If the actor cannot be contained by the proposed 084 * container. 085 * @exception NameDuplicationException 086 * If the container already has an actor with this name. 087 */ 088 public SVGToPolygon(CompositeEntity container, String name) 089 throws IllegalActionException, NameDuplicationException { 090 super(container, name); 091 092 fileOrURL = new FileParameter(this, "fileOrURL"); 093 094 output.setTypeEquals(BaseType.GENERAL); 095 trigger.setTypeEquals(BaseType.STRING); 096 097 _attachText("_iconDescription", "<svg>\n" 098 + "<rect x=\"-25\" y=\"-20\" " + "width=\"50\" height=\"40\" " 099 + "style=\"fill:white\"/>\n" 100 + "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14 3,-10" 101 + " 15,-10 15,10, -15,10\" " + "style=\"fill:red\"/>\n" 102 + "</svg>\n"); 103 } 104 105 // ///////////////////////////////////////////////////////////////// 106 // // ports and parameters //// 107 108 /** 109 * The file name or URL from which to read. This is a string with any form 110 * accepted by FileParameter. 111 * 112 * @see FileParameter 113 */ 114 public FileParameter fileOrURL; 115 116 /** 117 * Output the SVG file into a Polygons and their region names. 118 * 119 * @exception IllegalActionException 120 * If there's no director. 121 */ 122 public void fire() throws IllegalActionException { 123 if (trigger.getWidth() > 0) { 124 String fileName = ((StringToken) trigger.get(0)).stringValue(); 125 int lineEndInd = fileName.indexOf("\n"); 126 if (lineEndInd != -1) { // The string contains a CR. 127 fileName = fileName.substring(0, lineEndInd); 128 } 129 fileOrURL.setExpression(fileName.trim()); 130 } 131 input = fileOrURL.asFile(); 132 133 GeonXMLUtil parseXML = new GeonXMLUtil(); 134 135 Vector polyPoints = parseXML.getAttrValue(input, "polygon", "points"); 136 Vector regionsStr = parseXML.getElementsById(input, "polygon", 137 "onmouseover"); 138 139 // get conversion factors. 140 xRatio = ""; 141 yRatio = ""; // reset factors first. 142 _getConversionFactors(input); 143 144 // calculate parse tree for ratios. 145 PtParser parser = new PtParser(); 146 _parseTreeEvaluator = new ParseTreeEvaluator(); 147 _scope = new VariableScope(); 148 149 ASTPtRootNode _parseTreeX = null, _parseTreeY = null; 150 151 if (!xRatio.equals("")) 152 _parseTreeX = parser.generateParseTree(xRatio); 153 154 if (!yRatio.equals("")) 155 _parseTreeY = parser.generateParseTree(yRatio); 156 157 PolygonUtil polygonRegions[] = new PolygonUtil[polyPoints.size()]; 158 int beginInd, endInd; 159 for (int i = 0; i < polyPoints.size(); i++) { 160 161 // extract the polygon points. 162 String points = ((String) polyPoints.get(i)); 163 int iter = 0, ind = -1, comma = -1; 164 polygonRegions[i] = new PolygonUtil(); 165 polygonRegions[i].Poly = new DoublePolygon(); 166 while (iter < points.length()) { 167 ind = points.indexOf(' ', iter); 168 String point = points.substring(iter, ind); 169 iter = ind + 1; 170 comma = point.indexOf(','); 171 172 // processing the point by the conversion ratios. 173 double Px = Double.parseDouble(point.substring(0, comma)); 174 if (!xRatio.equals("")) { 175 param = Px; 176 Px = _ratioConvert(_parseTreeX); 177 } 178 double Py = Double.parseDouble(point.substring(comma + 1)); 179 if (!yRatio.equals("")) { 180 param = Py; 181 Py = _ratioConvert(_parseTreeY); 182 } 183 // System.out.println(Px+","+Py); 184 polygonRegions[i].Poly.addPoint(Px, Py); 185 if (ind == points.lastIndexOf(' ')) { 186 point = points.substring(ind + 1); 187 comma = point.indexOf(','); 188 Px = Double.parseDouble(point.substring(0, comma)); 189 if (!xRatio.equals("")) { 190 param = Px; 191 Px = _ratioConvert(_parseTreeX); 192 } 193 Py = Double.parseDouble(point.substring(comma + 1)); 194 if (!yRatio.equals("")) { 195 param = Py; 196 Py = _ratioConvert(_parseTreeY); 197 } 198 // System.out.println(Px+","+Py); 199 polygonRegions[i].Poly.addPoint(Px, Py); 200 iter = points.length(); 201 } 202 } 203 204 // extract the region. 205 String reg = ((String) regionsStr.get(i)); 206 /* 207 * beginInd = reg.indexOf('('); endInd = reg.indexOf(')'); reg = 208 * reg.substring(beginInd + 2, endInd - 1); 209 */ 210 polygonRegions[i].Region = reg; 211 } 212 output.broadcast(new ObjectToken(polygonRegions)); 213 } 214 215 /** 216 * Post fire the actor. Return false to indicate that the process has 217 * finished. If it returns true, the process will continue indefinitely. 218 */ 219 public boolean postfire() { 220 return true; 221 } 222 223 // ///////////////////////////////////////////////////////////////// 224 // // private methods //// 225 226 private void _getConversionFactors(File input) 227 throws IllegalActionException { 228 try { 229 DocumentBuilderFactory factory = DocumentBuilderFactory 230 .newInstance(); 231 factory.setValidating(false); 232 DocumentBuilder builder = factory.newDocumentBuilder(); 233 InputStream is = new FileInputStream(input); 234 Document doc = builder.parse(is); 235 236 NodeList nodes = doc.getElementsByTagName("conversion"); 237 for (int i = 0; i < nodes.getLength(); i++) { 238 String _id = ((Element) nodes.item(i)).getAttribute("id"); 239 String value = nodes.item(i).getFirstChild().getNodeValue(); 240 // String value = ( (Element) nodes.item(i)).getAttribute(_id); 241 if (_id.equals("toOriginalX")) 242 xRatio = value; 243 else if (_id.equals("toOriginalY")) 244 yRatio = value; 245 } 246 } catch (Exception ex) { 247 throw new IllegalActionException(this, "Error parsing SVG file " 248 + input); 249 } 250 } 251 252 private double _ratioConvert(ASTPtRootNode _parseTree) 253 throws IllegalActionException { 254 DoubleToken ratioToken = (DoubleToken) _parseTreeEvaluator 255 .evaluateParseTree(_parseTree, _scope); 256 if (ratioToken == null) { 257 throw new IllegalActionException(this, 258 "Expression yields a null result."); 259 } 260 return ratioToken.doubleValue(); 261 } 262 263 private class VariableScope extends ModelScope { 264 265 /** 266 * Look up and return the attribute with the specified name in the 267 * scope. Return null if such an attribute does not exist. 268 * 269 * @return The attribute with the specified name in the scope. 270 */ 271 public Token get(String name) throws IllegalActionException { 272 if (name.equals("val")) { 273 return new DoubleToken(param); 274 } else 275 return null; 276 } 277 278 /** 279 * Look up and return the type of the attribute with the specified name 280 * in the scope. Return null if such an attribute does not exist. 281 * 282 * @return The attribute with the specified name in the scope. 283 */ 284 public Type getType(String name) throws IllegalActionException { 285 if (name.equals("val")) { 286 return BaseType.DOUBLE; 287 } else 288 return null; 289 } 290 291 /** 292 * Look up and return the type term for the specified name in the scope. 293 * Return null if the name is not defined in this scope, or is a 294 * constant type. 295 * 296 * @return The InequalityTerm associated with the given name in the 297 * scope. 298 * @exception IllegalActionException 299 * If a value in the scope exists with the given name, 300 * but cannot be evaluated. 301 */ 302 public ptolemy.graph.InequalityTerm getTypeTerm(String name) 303 throws IllegalActionException { 304 if (name.equals("val")) { 305 return new TypeConstant(BaseType.DOUBLE); 306 } else 307 return null; 308 } 309 310 /** 311 * Return the list of identifiers within the scope. 312 * 313 * @return The list of identifiers within the scope. 314 */ 315 public Set identifierSet() { 316 return getAllScopedVariableNames(null, SVGToPolygon.this); 317 } 318 } 319 320 // ///////////////////////////////////////////////////////////////// 321 // // private members //// 322 323 /** Previous value of fileOrURL parameter. */ 324 private String _previousFileOrURL; 325 private File input; 326 private String xRatio = "", yRatio = ""; 327 private double param; 328 // private ASTPtRootNode _parseTree = null; 329 private ParseTreeEvaluator _parseTreeEvaluator = null; 330 private VariableScope _scope = null; 331 332}