+++ /dev/null
-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.sysdyn.mdlImport;\r
-\r
-import java.awt.geom.Point2D;\r
-import java.io.BufferedReader;\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileReader;\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-import java.io.Reader;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import org.simantics.sysdyn.mdlImport.model.Auxiliary;\r
-import org.simantics.sysdyn.mdlImport.model.Cloud;\r
-import org.simantics.sysdyn.mdlImport.model.Connection;\r
-import org.simantics.sysdyn.mdlImport.model.Dependency;\r
-import org.simantics.sysdyn.mdlImport.model.Element;\r
-import org.simantics.sysdyn.mdlImport.model.EquivalenceSubscript;\r
-import org.simantics.sysdyn.mdlImport.model.Expression;\r
-import org.simantics.sysdyn.mdlImport.model.Flow;\r
-import org.simantics.sysdyn.mdlImport.model.Function;\r
-import org.simantics.sysdyn.mdlImport.model.Model;\r
-import org.simantics.sysdyn.mdlImport.model.Model2;\r
-import org.simantics.sysdyn.mdlImport.model.Stock;\r
-import org.simantics.sysdyn.mdlImport.model.Subscript;\r
-import org.simantics.sysdyn.mdlImport.model.Valve;\r
-import org.simantics.sysdyn.mdlImport.model.Variable;\r
-import org.simantics.sysdyn.mdlImport.model.View;\r
-\r
-/*\r
- * THINGS TO FIX:\r
- * - vensim apparently supports infix operators (:AND: instead of AND()), these must be handled\r
- * - "public" seems to be a keyboard of some sort which causes a problem in certain variable names\r
- * - something is seriously wrong with the sketch import\r
- * - how should models with multiple sketches be handled (this might already work)\r
- * - instead of splitting the file into blocks, the parser could already process the data further which would greatly simplify later methods\r
- */\r
-\r
-public class MdlParser {\r
-\r
- private enum State {\r
- VARIABLE, CONTROL, SKETCH, OTHER\r
- }\r
- \r
- public static Model parse(File file) {\r
- \r
- Model2 model = new Model2(file.getName());\r
- \r
- try {\r
- // peek at the first line to see if we need to use UTF-8\r
- BufferedReader reader = new BufferedReader(new FileReader(file));\r
- String line = reader.readLine();\r
- reader.close();\r
- \r
- if (line == null) {\r
- // file is empty, nothing to do here\r
- return null;\r
- }\r
- \r
- if (line.startsWith(UTF_8)) {\r
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));\r
- // skip the first line\r
- reader.readLine();\r
- }\r
- else {\r
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));\r
- }\r
- \r
- // read the model structure from the file contents\r
- readVariables(reader, model);\r
- readControls(reader, model);\r
- readSketches(reader, model);\r
- readOthers(reader, model);\r
- }\r
- catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
- \r
- return null;\r
- }\r
-\r
- public static Model parse2(File file) {\r
-\r
- Model2 model = new Model2(file.getName());\r
-\r
- //String[] name = file.getName().split("\\.mdl");\r
- //model.setName(name[0]);\r
-\r
- MdlFile mdlFile = getMdlFile(file);\r
-\r
- for (String variable : mdlFile.getVariableData()) {\r
- parseElement(variable);\r
- }\r
-\r
- for (ArrayList<String> sketch : mdlFile.getSketchData()) {\r
- parseSketch(sketch);\r
- }\r
-\r
- //MdlFile test = getMdlContents(file);\r
-\r
- //getVariableData(model, test.getVariableData());\r
-\r
- //getSketchData(model, mdlFile.getSketchData());\r
-\r
- //getControlData(model, mdlFile.getControlData());\r
-\r
- //getOthertData(model, mdlFile.getOtherData());\r
-\r
- //setAllSubscripts(model);\r
-\r
- return null;\r
- }\r
-\r
- private static final String UTF_8 = "{UTF-8}";\r
- private static final String CONTROL_STR = ".Control";\r
- private static final String SKETCH_START = "\\\\\\---///";\r
- private static final String SKETCH_END = "///---\\\\\\";\r
-\r
- private static MdlFile getMdlFile(File file) {\r
- MdlFile mdl = new MdlFile();\r
-\r
- try {\r
- BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));\r
- String line = reader.readLine();\r
-\r
- if (line != null && line.startsWith(UTF_8)) {\r
- reader.close();\r
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));\r
- // skip the "{UTF-8}" line\r
- reader.readLine();\r
- line = reader.readLine();\r
- }\r
-\r
- State state = State.VARIABLE;\r
-\r
- while (line != null) {\r
- line = line.trim();\r
-\r
- // skip all empty lines\r
- if (line.isEmpty()) {\r
- line = reader.readLine();\r
- continue;\r
- }\r
-\r
- switch (state) {\r
- // the file starts with variable declarations that always \r
- // start with a variable name and end with a '|'\r
- case VARIABLE:\r
- if (line.startsWith(SKETCH_START)) {\r
- state = State.SKETCH;\r
- continue; \r
- }\r
-\r
- String variable = readVariable(reader, line);\r
-\r
- // simulation control variables are separated from model \r
- // variables with a control block that looks basically\r
- // like a variable but can be safely ignored\r
- if (variable.contains(CONTROL_STR)) {\r
- state = State.CONTROL;\r
- break;\r
- }\r
-\r
- mdl.addVariableData(variable);\r
- break;\r
-\r
- // simulation control variables look like model variables but\r
- // are handled differently\r
- case CONTROL:\r
- if (line.startsWith(SKETCH_START)) {\r
- state = State.SKETCH;\r
- continue; \r
- }\r
-\r
- String control = readVariable(reader, line);\r
- mdl.addControlData(control);\r
- break;\r
-\r
- // sketch information contains the details on the structure\r
- // and the visual representation of the model and is situated\r
- // in the file after variable declarations\r
- case SKETCH:\r
- if (line.startsWith(SKETCH_END)) {\r
- state = State.OTHER;\r
- break;\r
- }\r
-\r
- if (line.startsWith(SKETCH_START)) {\r
- mdl.startSketch();\r
- break;\r
- }\r
-\r
- mdl.addSketchData(line);\r
- break;\r
-\r
- // the file ends with a section of data that contains some\r
- // additional information which is not handled currently\r
- case OTHER:\r
- mdl.addOtherData(line);\r
- break;\r
-\r
- default: break; // should not get this far\r
- }\r
-\r
- line = reader.readLine();\r
- }\r
-\r
- reader.close();\r
- }\r
- catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
-\r
- return mdl;\r
- }\r
- \r
- private static void readVariables(BufferedReader reader, Model2 model) \r
- throws IOException {\r
- StringBuilder buffer = new StringBuilder();\r
- \r
- String line = reader.readLine();\r
- while (line != null && !line.startsWith(SKETCH_START)) {\r
- if (line.endsWith("\\")) {\r
- buffer.append(line.substring(0, line.length()-1));\r
- }\r
- else {\r
- buffer.append(line);\r
- }\r
- \r
- if (line.endsWith("|")) {\r
- parseElement(buffer.toString());\r
- buffer.setLength(0);\r
- }\r
- }\r
- }\r
- \r
- private static void readControls(BufferedReader reader, Model2 model) \r
- throws IOException {\r
- String line = reader.readLine();\r
- while (line != null && !line.startsWith(SKETCH_START)) {\r
- \r
- }\r
- }\r
- \r
- private static void readSketches(BufferedReader reader, Model2 model) \r
- throws IOException {\r
- \r
- }\r
- \r
- private static void readOthers(BufferedReader reader, Model2 model) \r
- throws IOException {\r
- \r
- }\r
- \r
-\r
- private static String readVariable(BufferedReader reader, String current) \r
- throws IOException {\r
- // TODO: does not support subscript stuff at all currently\r
- StringBuilder element = new StringBuilder();\r
-\r
- while (current != null) {\r
- current = current.trim().replace('\t', ' ');\r
-\r
- if (current.endsWith("|")) {\r
- element.append(current.substring(0, current.length() - 1));\r
- break;\r
- }\r
- else if (current.endsWith("\\")) {\r
- element.append(current.substring(0, current.length() - 1));\r
- }\r
- else {\r
- element.append(current);\r
- }\r
-\r
- current = reader.readLine();\r
- }\r
-\r
- return element.toString();\r
- }\r
-\r
- private static void parseElement(String element) {\r
- String left, right, unit, desc;\r
-\r
- String[] data = element.split("~");\r
-\r
- if (data.length != 3) {\r
- System.err.println("INVALID ELEMENT DATA "+element);\r
- return;\r
- }\r
-\r
- String equation = normalize(data[0]);\r
-\r
- left = equation.substring(0, equation.indexOf('=')).trim();\r
- right = equation.substring(equation.indexOf('=') + 1).trim();\r
- unit = data[1].trim();\r
- desc = data[2].trim();\r
-\r
- //System.err.println("FOUND VARIABLE "+left);\r
- //System.err.println(" EQUATION "+right);\r
- //System.err.println(" UNIT "+unit);\r
- //System.err.println(" DESC "+desc);\r
-\r
- }\r
-\r
- // TODO: name should probably be escaped just before writing to graph\r
- \r
- // matches a quoted string that may contain escaped special characters \r
- // (which includes other quotation marks)\r
- private static final String QUOTED_PATTERN = "\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"";\r
- // matches (possibly escaped) unsupported characters\r
- private static final String BADCHARS_PATTERN = "\\\\?[-+*/()=<>\"]";\r
- // matches a substring that should be capitalized (see below for details)\r
- private static final String NAMEPART_PATTERN = "([A-Za-z])[A-Za-z]*";\r
-\r
- // normalize a variable name\r
- private static String normalize(String str) {\r
- StringBuilder result = new StringBuilder(str);\r
-\r
- Matcher matcher;\r
-\r
- matcher = Pattern.compile(QUOTED_PATTERN).matcher(str);\r
- while (matcher.find()) {\r
- // TODO: could do something more clever than just an underscore\r
- String replacement = Pattern.compile(BADCHARS_PATTERN).matcher(matcher.group(1)).replaceAll("_");\r
- result.replace(matcher.start(), matcher.end(), replacement);\r
- }\r
-\r
- // also capitalize all variable names to remove certain openmodelica \r
- // keywords such as "public" or "private", this might not seem like\r
- // the most sane variable name handling scheme possible, but it is\r
- // nevertheless the one we are forced to use \r
- matcher = Pattern.compile(NAMEPART_PATTERN).matcher(result.toString());\r
- while (matcher.find()) {\r
- // replace the first character of the match with the same \r
- // character in upper case\r
- result.replace(matcher.start(1), matcher.end(1), matcher.group(1).toUpperCase());\r
- }\r
-\r
- return result.toString();\r
- }\r
-\r
- private static void parseSketch(ArrayList<String> sketch) {\r
- // the sketch should have at least three lines, version, name and font\r
- if (sketch.size() < 3 || \r
- !sketch.get(0).startsWith("V300") || \r
- !sketch.get(1).startsWith("*") || \r
- !sketch.get(2).startsWith("$")) {\r
- System.err.println("INVALID SKETCH DATA");\r
- return;\r
- }\r
-\r
- // parse name\r
- String name = sketch.get(1).substring(1);\r
- // parse font\r
- String font = sketch.get(2).substring(2);\r
-\r
- for (int i = 3; i < sketch.size(); i++) {\r
- String line = sketch.get(i);\r
- if (line.startsWith(CONNECTION_PREFIX)) {\r
- parseConnection(line.substring(2));\r
- }\r
- else if (line.startsWith(VARIABLE_PREFIX)) {\r
- parseVariable(line.substring(3));\r
- }\r
- else if (line.startsWith(VALVE_PREFIX)) {\r
- //parseValve(line.substring(3));\r
- }\r
- else if (line.startsWith(COMMENT_PREFIX)) {\r
- //parseComment(line.substring(3));\r
- }\r
- else {\r
- //System.err.println("UNSUPPORTED SKETCH OBJECT "+line);\r
- }\r
- }\r
- }\r
-\r
- // these methods are implemented according to the documentation on the .mdl\r
- // file format available in http://www.vensim.com/documentation/24305.htm\r
-\r
- // (1,)id,from,to,shape,hid,pol,thick,hasf,dtype,res,color,font,np|plist\r
- private static final String CONNECTION_PREFIX = "1,";\r
- private static final String CONNECTION_PATTERN = \r
- "(\\d+),(\\d+),(\\d+).*";\r
- // (n,)id,name,x,y,w,h,sh,bits,hid,hasf,tpos,bw,nav1,nav2(,box,fill,font)\r
- private static final String VARIABLE_PREFIX = "10,";\r
- private static final String VALVE_PREFIX = "11,";\r
- private static final String COMMENT_PREFIX = "12,";\r
- private static final String ELEMENT_PATTERN = \r
- "(\\d+),(\".*\"|[^\",]*),(-?\\d+),(-?\\d+),(\\d+),(\\d+).*";\r
-\r
- private static void parseConnection(String line) {\r
- Matcher matcher = Pattern.compile(CONNECTION_PATTERN).matcher(line);\r
- if (!matcher.matches()) {\r
- System.err.println("MALFORMED CONNECTION");\r
- return;\r
- }\r
-\r
- // the fields of interest are: id, from, to, ... (TODO)\r
- int id = Integer.parseInt(matcher.group(1));\r
- int from = Integer.parseInt(matcher.group(2));\r
- int to = Integer.parseInt(matcher.group(3));\r
-\r
- System.err.println("connection "+id+": "+from+" -> "+to);\r
- }\r
-\r
- private static void parseVariable(String line) {\r
- Matcher matcher = Pattern.compile(ELEMENT_PATTERN).matcher(line);\r
- if (!matcher.matches()) {\r
- System.err.println("MALFORMED VARIABLE "+line);\r
- return;\r
- }\r
- \r
- int id = Integer.parseInt(matcher.group(1));\r
- String name = normalize(matcher.group(2));\r
- int x = Integer.parseInt(matcher.group(3));\r
- int y = Integer.parseInt(matcher.group(4));\r
- int width = Integer.parseInt(matcher.group(5));\r
- int height = Integer.parseInt(matcher.group(6));\r
- \r
- System.err.println("variable "+id+": "+name+" ("+x+","+y+")");\r
- }\r
-\r
- private static void parseValve(String line) {\r
- \r
- }\r
-\r
- private static void parseComment(String line) { \r
- \r
- }\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
- private static MdlFile getMdlContents(File aFile) {\r
- MdlFile mdlFile = new MdlFile();\r
-\r
- try {\r
- BufferedReader input = new BufferedReader(new FileReader(aFile));\r
-\r
- try {\r
- String line = null; // not declared within while loop\r
- \r
- mdlFile.startSketch();\r
-\r
- // See if the document is encoded with UTF-8. It will be marked with {UTF-8} on the first line\r
- input.mark(30);\r
- if ((line = input.readLine()) != null && line.contains("{UTF-8}")){\r
- Reader in = new InputStreamReader(new FileInputStream(aFile), "UTF-8");\r
- input = new BufferedReader(in);\r
- line = input.readLine();\r
- } else {\r
- input.reset();\r
- }\r
-\r
-\r
- boolean isControl = false;\r
-\r
- while ((line = input.readLine()) != null) {\r
- // Build an element (combine the lines to one string)\r
- StringBuilder elementBuilder = new StringBuilder();\r
- while (line != null && !line.contains("\\\\\\---///")) {\r
- // Add a new line for the element\r
- elementBuilder.append(line);\r
- if(line.endsWith("|") && !line.endsWith("~~|")) {\r
- //Element definition has ended\r
- break;\r
- }\r
- line = input.readLine();\r
- }\r
-\r
- if (line.contains("\\\\\\---///"))\r
- break;\r
-\r
- String variable = elementBuilder.toString();\r
-\r
- if (variable.trim().matches("[\\*]{46}.+[\\*]{46}.+")) {\r
- if(variable.contains(".Control")) {\r
- isControl = true;\r
- } else {\r
- isControl = false;\r
- }\r
- continue;\r
- }\r
-\r
- // Add element string to model\r
- if(isControl) {\r
- mdlFile.addControlData(variable);\r
- } else {\r
- mdlFile.addVariableData(variable);\r
- }\r
- }\r
-\r
- while ((line = input.readLine()) != null && !line.contains("///---\\\\\\")) {\r
- mdlFile.addSketchData(line);\r
- }\r
-\r
- while ((line = input.readLine()) != null){\r
- mdlFile.addOtherData(line);\r
- }\r
- }\r
- finally {\r
- input.close();\r
- }\r
- }\r
- catch (IOException ex){\r
- ex.printStackTrace();\r
- }\r
-\r
- return mdlFile;\r
- }\r
-\r
- private static void getVariableData(Model model, ArrayList<String> elements) {\r
- ArrayList<EquivalenceSubscript> equivalenceSubscripts = new ArrayList<EquivalenceSubscript>();\r
- for(String elementString : elements) {\r
- Variable v = createVariable(model, elementString);\r
- if(v instanceof EquivalenceSubscript){\r
- equivalenceSubscripts.add((EquivalenceSubscript) v);\r
- }\r
- }\r
-\r
- // All variables are ready, determine subscript equivalences\r
- for(EquivalenceSubscript es : equivalenceSubscripts) {\r
- Element e = model.getElement(es.getEquivalentToName());\r
- if(e != null && e instanceof Subscript) {\r
- es.setEquivalentTo((Subscript)e);\r
- }\r
- }\r
- }\r
-\r
-\r
- private static void getControlData(Model model, ArrayList<String> controls) {\r
- for(String controlString : controls) {\r
- String[] nameAndData = controlString.split("="); \r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
-\r
- if(nameAndData[0].trim().equals("FINAL TIME")) {\r
- model.setEndTime(Double.parseDouble(expressionUnitsAndComments[0]));\r
- } else if(nameAndData[0].trim().equals("INITIAL TIME")) {\r
- model.setStartTime(Double.parseDouble(expressionUnitsAndComments[0]));\r
- } else if(nameAndData[0].trim().equals("TIME STEP")) {\r
- model.setTimeStep(Double.parseDouble(expressionUnitsAndComments[0]));\r
- } else if(nameAndData[0].trim().equals("SAVEPER")) {\r
- model.setSaveper(expressionUnitsAndComments[0]);\r
- model.setTimeUnit(expressionUnitsAndComments[1]);\r
- }\r
- }\r
-\r
- }\r
-\r
- private static Variable getVariable(Model model, String name) {\r
- Element e = model.getElement(name);\r
- Variable variable = null;\r
- if(e != null && e instanceof Variable)\r
- variable = (Variable)e;\r
- return variable;\r
- }\r
-\r
- private static String[] getNormalVariableNameDataAndRange(String element) {\r
- String[] nameAndData = element.split("=", 2);\r
- String[] nameAndRange = nameAndData[0].trim().split("[\\[|\\]]");\r
- if(nameAndData.length == 2)\r
- return new String[] {nameAndRange[0], nameAndData[1], nameAndRange.length == 2 ? nameAndRange[1] : null};\r
- return null;\r
- }\r
-\r
- private static String[] getSubscriptNameAndData(String element) {\r
- String[] nameAndData = element.split(":");\r
- if(nameAndData.length == 2)\r
- return nameAndData;\r
- return null;\r
- } \r
-\r
- private static String[] getEquivalenceSubscriptNameAndData(String element) {\r
- String[] nameAndData = element.split("\\<\\-\\>");\r
- if(nameAndData.length == 2)\r
- return nameAndData;\r
- return null;\r
- }\r
-\r
- private static String[] getTableNameDataAndRange(String element) {\r
- String[] parts = element.split("\\~"); \r
- if(!parts[0].contains("(") || !parts[0].contains(")"))\r
- return null;\r
- String name = element.substring(0, element.indexOf("("));\r
- String theRest = element.substring(element.indexOf("("));\r
- String[] nameAndData = {name, theRest};\r
- String[] nameAndRange = nameAndData[0].trim().split("[\\[|\\]]");\r
- if(nameAndData.length == 2)\r
- return new String[] {nameAndRange[0], nameAndData[1], nameAndRange.length == 2 ? nameAndRange[1] : null};\r
- return nameAndData;\r
- }\r
-\r
- private static String[] getDataVariableNameAndData(String element) {\r
- String[] nameAndData = {\r
- element.substring(0, element.indexOf("~")),\r
- " " + element.substring(element.indexOf("~"))};\r
- return nameAndData;\r
- }\r
-\r
- private static Variable createVariable(Model model, String elementString) {\r
-\r
- String[] elementExpressions = elementString.split("\\~\\~\\|");\r
-\r
- Variable variable = null;\r
- \r
- System.err.println("CREATE VARIABLE "+elementString);\r
-\r
- for(String s : elementExpressions) {\r
- System.err.println(" INSIDE FOR");\r
- \r
- // Skip these definitions at least for now\r
- if(elementExpressions.length > 1 && s.contains("A FUNCTION OF"))\r
- continue;\r
-\r
- Expression expression = new Expression();\r
-\r
- String[] nameAndData = null;\r
- String name;\r
-\r
- // Create the expression based on the expression string\r
- if((nameAndData = getNormalVariableNameDataAndRange(s)) != null) {\r
-\r
- name = nameAndData[0].replace("\"", "");\r
- variable = getVariable(model, name);\r
- if(variable == null) {\r
- variable = new Auxiliary();\r
- variable.setName(name);\r
- model.addElement(variable);\r
- }\r
-\r
- if(!nameAndData[1].trim().endsWith("|")) {\r
- // Multiple expressions\r
- expression.setExpression(nameAndData[1].trim());\r
- } else {\r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
- expression.setExpression(expressionUnitsAndComments[0].trim());\r
- }\r
-\r
- } else if((nameAndData = getSubscriptNameAndData(s)) != null) {\r
-\r
- name = nameAndData[0].replace("\"", "");\r
- variable = getVariable(model, name);\r
- if(variable == null) {\r
- variable = new Subscript();\r
- variable.setName(name);\r
- model.addElement(variable);\r
- }\r
-\r
- // No support for multidimensional variables. Don't know what that would mean\r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
- expression.setExpression(expressionUnitsAndComments[0].trim());\r
- variable.setUnits(expressionUnitsAndComments[1].trim());\r
- variable.setComments(expressionUnitsAndComments[2].trim());\r
-\r
- } else if((nameAndData = getEquivalenceSubscriptNameAndData(s)) != null) {\r
-\r
- name = nameAndData[0].replace("\"", "");\r
- variable = getVariable(model, name);\r
- if(variable == null) {\r
- variable = new EquivalenceSubscript();\r
- variable.setName(name);\r
- model.addElement(variable);\r
- }\r
-\r
- // No support for multidimensional variables. Don't know what that would mean\r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
- expression.setExpression(expressionUnitsAndComments[0].trim());\r
- variable.setUnits(expressionUnitsAndComments[1].trim());\r
- variable.setComments(expressionUnitsAndComments[2].trim());\r
-\r
- } else if((nameAndData = getTableNameDataAndRange(s)) != null) {\r
-\r
- name =(nameAndData[0].replace("\"", ""));\r
- variable = getVariable(model, name);\r
- if(variable == null) {\r
- variable = new Function();\r
- variable.setName(name);\r
- model.addElement(variable);\r
- }\r
-\r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
- // ([(0,0)-(2,5)],(0,5),(0.5,3),(1,0.5),(2,0.5) => ( ; (0,0)-(2,5) ; ,(0,5),(0.5,3),(1,0.5),(2,0.5)\r
- String table = expressionUnitsAndComments[0].trim().split("[\\[|\\]]")[2];\r
- // ,(0,5),(0.5,3),(1,0.5),(2,0.5) => (0,5),(0.5,3),(1,0.5),(2,0.5)\r
- table = table.substring(table.indexOf(",") + 1, table.lastIndexOf(")"));\r
- table = "{" + table + "}";\r
- table = table.replace("(", "{");\r
- table = table.replace(")", "}");\r
- expression.setExpression(table); \r
-\r
-\r
- } else if((nameAndData = getDataVariableNameAndData(s)) != null) {\r
-\r
- name = nameAndData[0].replace("\"", "");\r
- variable = getVariable(model, name);\r
- if(variable == null) {\r
- variable = new Auxiliary();\r
- variable.setName(name);\r
- model.addElement(variable);\r
- }\r
-\r
- expression.setExpression("");\r
- } \r
-\r
- if(nameAndData == null || variable == null)\r
- continue;\r
-\r
- // Set possible range for the expression\r
- if(nameAndData.length == 3)\r
- expression.setRange(nameAndData[2]);\r
-\r
- // Set units and comments for the variable \r
- if(nameAndData[1].trim().endsWith("|")) {\r
- String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]");\r
- String units = expressionUnitsAndComments[1].trim();\r
- if(units.contains("[") &&\r
- units.contains("]") &&\r
- units.lastIndexOf("]") == units.length() - 1) {\r
- // Range definitions are at the end\r
- String range = units.substring(\r
- units.lastIndexOf("[") + 1, \r
- units.length() - 1);\r
- String[] rangeParts = range.split(",");\r
-\r
- try {\r
- variable.setRangeStart(Double.parseDouble(rangeParts[0]));\r
- if(rangeParts.length >= 2)\r
- variable.setRangeEnd(Double.parseDouble(rangeParts[1]));\r
- if(rangeParts.length >= 3)\r
- variable.setRangeStep(Double.parseDouble(rangeParts[2]));\r
- } catch (NumberFormatException e) {\r
- // Not a double\r
- }\r
- expressionUnitsAndComments[1] = units.substring(0, units.lastIndexOf("["));\r
- }\r
- variable.setUnits(expressionUnitsAndComments[1].trim());\r
- variable.setComments(expressionUnitsAndComments[2].trim());\r
- }\r
-\r
- // Finally add the expression to element\r
- variable.getExpressions().add(expression);\r
- }\r
- return variable;\r
- }\r
-\r
- private static int SCALE = 4;\r
-\r
- private static void getSketchData(Model model, ArrayList<String> sketchData) {\r
- String line = null;\r
- View view = null;\r
-\r
- int i = 0;\r
-\r
- while(i < sketchData.size()) {\r
- line = sketchData.get(i);\r
- if(line.startsWith("*")) {\r
- view = new View();\r
- model.addView(view);\r
-\r
- view.setName(line.substring(1));\r
-\r
- // STARTED A NEW VIEW\r
-\r
- HashMap<String, Element> elementNumbers = new HashMap<String, Element>();\r
- ArrayList<String> ghostNumbers = new ArrayList<String>();\r
- ArrayList<String[]> connections = new ArrayList<String[]>();\r
- HashMap<String, String[]> emptyValves = new HashMap<String, String[]>(); // map for valves that don't have an element \r
-\r
-\r
- i++;\r
- line = sketchData.get(i);\r
- while(i < sketchData.size() && !sketchData.get(i).startsWith("*")) {\r
- line = sketchData.get(i);\r
-\r
- if(line.startsWith("$")) {\r
- view.setFontParameters(line);\r
- i++;\r
- continue;\r
- }\r
-\r
- String[] data = line.split(",");\r
- if (data[0].equals("1")) {\r
- // Connections are handled after all elements\r
- String[] connectionData = line.split(",");\r
- connections.add(connectionData);\r
-\r
- } else if (data[0].equals("11")){\r
- // Valve\r
- i = i + 1;\r
- String elementLine = sketchData.get(i);\r
- String[] elementData = elementLine.split(",");\r
- // FIXME: Assumes that element is always attached to the valve\r
- Element element = model.getElement(elementData[2].replace("\"", ""));\r
- Valve valve = new Valve();\r
- if (element != null && element instanceof Variable) {\r
- Variable v = (Variable) element;\r
- valve.setName(v.getName());\r
- valve.setExpressions(v.getExpressions());\r
- valve.setUnits(v.getUnits());\r
- valve.setComments(v.getComments());\r
- valve.setX(Integer.parseInt(data[3]) / SCALE);\r
- valve.setY(Integer.parseInt(data[4]) / SCALE);\r
-\r
- model.removeElement(element);\r
- model.addElement(view, valve);\r
-\r
- // Add valve to the element list with both valve and variable symbol numbers\r
- elementNumbers.put(elementData[1], valve);\r
- elementNumbers.put(data[1], valve);\r
- } else {\r
- i = i - 1;\r
- emptyValves.put(data[1], data);\r
- }\r
- } else if (data[0].equals("12")){\r
- // Cloud\r
- Cloud cloud = new Cloud();\r
- cloud.setX(Integer.parseInt(data[3]) / SCALE); \r
- cloud.setY(Integer.parseInt(data[4]) / SCALE); \r
- elementNumbers.put(data[1], cloud);\r
- model.addElement(view, cloud);\r
- } else if (data[0].equals("10") && data.length <= 15){\r
- // Some variable\r
- Element e = model.getElement(data[2].replace("\"", "").trim());\r
-\r
- if (e != null && e instanceof Variable) {\r
- Variable v = (Variable) e;\r
- if (v.getExpressions().get(0).getExpression().startsWith("INTEG (") && !(e instanceof Stock)) {\r
- // Stock\r
- Stock s = new Stock();\r
- s.setName(v.getName());\r
- s.setUnits(v.getUnits());\r
- s.setComments(v.getComments());\r
- s.setExpressions(v.getExpressions());\r
- model.removeElement(e);\r
- e = s;\r
- model.addElement(view, e);\r
- }\r
- }\r
-\r
- e.setX(Integer.parseInt(data[3]) / SCALE); \r
- e.setY(Integer.parseInt(data[4]) / SCALE); \r
- elementNumbers.put(data[1], e);\r
- model.relocateElement(view, e);\r
- } else if (data[0].equals("10") && data.length > 15){\r
- // TODO: Ghost\r
- // for now, direct back to the original element\r
- Element originalElement = model.getElement(data[2].replace("\"", ""));\r
- if(originalElement != null) {\r
- elementNumbers.put(data[1], originalElement);\r
- ghostNumbers.add(data[1]);\r
- }\r
- }\r
-\r
- i++;\r
- }\r
-\r
- i--;\r
-\r
- // Find the first variable that is connected to an empty valve\r
- for(String[] connectionData : connections) {\r
- if(!connectionData[9].equals("64"))\r
- continue; // not dependency\r
- String[] end = emptyValves.get(connectionData[3]);\r
- if (end != null && elementNumbers.get(connectionData[3]) == null) {\r
- // Use the connected element to create a valve and give it a name \r
- Element start = elementNumbers.get(connectionData[2]);\r
- if (start == null)\r
- continue;\r
-\r
- Valve valve = new Valve();\r
- valve.setName(start.getName() + " Rate");\r
- valve.setX(Integer.parseInt(end[3]) / SCALE); \r
- valve.setY(Integer.parseInt(end[4]) / SCALE);\r
-\r
- model.addElement(view, valve);\r
- elementNumbers.put(connectionData[3], valve);\r
- valve.setUnits("");\r
- valve.setComments("");\r
- }\r
- }\r
-\r
-\r
-\r
- for(String[] connectionData : connections) {\r
-\r
- Element start = elementNumbers.get(connectionData[2]);\r
- Element end = elementNumbers.get(connectionData[3]);\r
- // Discard connection if one of the ends is null\r
- if(start == null || end == null)\r
- continue;\r
-\r
-\r
- Connection connection; \r
- if(connectionData[9].equals("64")) {\r
- // Dependency\r
- Point2D startPoint = new Point2D.Double(start.getX(), start.getY());\r
- Point2D endPoint = new Point2D.Double(end.getX(), end.getY());\r
- String controlX = connectionData[13].substring(connectionData[13].indexOf("(") + 1);\r
- String controlY = connectionData[14].substring(0, connectionData[14].indexOf(")"));\r
- Point2D controlPoint = new Point2D.Double(Double.parseDouble(controlX) / SCALE, Double.parseDouble(controlY) / SCALE);\r
-\r
- if(ghostNumbers.contains(connectionData[2]) ||\r
- ghostNumbers.contains(connectionData[3])) {\r
- connection = new Dependency();\r
- } else {\r
- double angle = Dependency.angleOfArc(\r
- startPoint.getX(), startPoint.getY(),\r
- controlPoint.getX(), controlPoint.getY(),\r
- endPoint.getX(), endPoint.getY());\r
-\r
- connection = new Dependency(angle);\r
- }\r
-\r
- } else {\r
- // Flow\r
- connection = new Flow();\r
- if(connectionData[4].equals("100")) {\r
- // Flip the flow\r
- Element temp = start;\r
- start = end;\r
- end = temp;\r
- }\r
- }\r
- connection.setStart(start);\r
- connection.setEnd(end);\r
- model.addConnection(connection);\r
- }\r
-\r
-\r
- // Generate expressions for empty valves \r
- for(String key : emptyValves.keySet()) {\r
- Element e = elementNumbers.get(key);\r
- if(e instanceof Valve && ((Valve)e).getExpressions().isEmpty()) {\r
- Valve valve = (Valve)e;\r
- // Find the stock\r
- Stock stock = null;\r
- for(Connection connection : valve.getConnections()) {\r
- if(!(connection instanceof Flow))\r
- continue;\r
- if(connection.getStart().equals(valve) &&\r
- connection.getEnd() instanceof Stock) {\r
- stock = (Stock)connection.getEnd();\r
- break;\r
- }\r
- }\r
-\r
- // Create the expression. Use the expression of the stock, and undo the effect of other valves\r
- if(stock != null && stock instanceof Stock) {\r
- Expression expression = new Expression();\r
-\r
- StringBuilder sb = new StringBuilder();\r
- sb.append(((Stock)stock).getIntegralParts(stock.getExpressions().get(0))[0]);\r
-\r
- for(Connection c : stock.getConnections()) {\r
- if(c instanceof Flow) {\r
- if(c.getStart().equals(stock) && !c.getEnd().equals(valve)) {\r
- sb.append("+");\r
- sb.append(c.getEnd().getName());\r
- } else if(!c.getStart().equals(valve)){\r
- sb.append("-");\r
- sb.append(c.getStart().getName());\r
- }\r
- }\r
- }\r
- expression.setExpression(sb.toString());\r
- ArrayList<Expression> expressions = new ArrayList<Expression>();\r
- expressions.add(expression);\r
- valve.setExpressions(expressions);\r
- }\r
- }\r
- }\r
- }\r
-\r
- i++;\r
- }\r
-\r
- }\r
-\r
- private static void getOthertData(Model model, String otherData) {\r
-\r
- }\r
-\r
- private static void setAllSubscripts(Model model) {\r
-\r
- // Set subscripts for all elements\r
- ArrayList<Element> elements = new ArrayList<Element>();\r
- elements.addAll(model.getUnlocatedElements());\r
- for(View view : model.getViews()) {\r
- elements.addAll(view.getElements());\r
- }\r
-\r
- for(Element e : elements) { \r
- if(!(e instanceof Variable))\r
- continue;\r
- Variable v = (Variable)e;\r
- v.initializeSubscripts(model);\r
- }\r
- }\r
-\r
-}\r
+++ /dev/null
-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.sysdyn.mdlImport;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-\r
-import org.simantics.sysdyn.mdlImport.model.Connection2;\r
-import org.simantics.sysdyn.mdlImport.model.Element2;\r
-import org.simantics.sysdyn.mdlImport.model.Model;\r
-import org.simantics.sysdyn.mdlImport.model.Model2;\r
-import org.simantics.sysdyn.mdlImport.model.Sketch2;\r
-import org.simantics.sysdyn.mdlImport.model.SketchComment;\r
-import org.simantics.sysdyn.mdlImport.model.SketchConnection;\r
-import org.simantics.sysdyn.mdlImport.model.SketchElement;\r
-import org.simantics.sysdyn.mdlImport.model.SketchValve;\r
-import org.simantics.sysdyn.mdlImport.model.SketchVariable;\r
-import org.simantics.sysdyn.mdlImport.model.Variable2;\r
-\r
-/*\r
- * THINGS TO FIX:\r
- * - vensim apparently supports infix operators (:AND: instead of AND()), these must be handled\r
- * - "public" seems to be a keyboard of some sort which causes a problem in certain variable names\r
- * - something is seriously wrong with the sketch import\r
- * - how should models with multiple sketches be handled (this might already work)\r
- * - instead of splitting the file into blocks, the parser could already process the data further which would greatly simplify later methods\r
- */\r
-\r
-public class MdlParser2 {\r
-\r
- private static final String UTF_8 = "{UTF-8}";\r
- private static final String CONTROL_STR = ".Control";\r
- private static final String SKETCH_VERSION = "V300";\r
- \r
- // each .mdl is divided into three sections, these are the the delimiter\r
- // strings used to identify where each section starts\r
- private static final String SKETCH_START = "\\\\\\---///";\r
- private static final String SKETCH_END = "///---\\\\\\";\r
-\r
- private HashMap<String, Variable2> variables;\r
- private HashMap<String, Variable2> controls;\r
- private ArrayList<Sketch2> sketches;\r
-\r
- public MdlParser2() {\r
- variables = new HashMap<String, Variable2>();\r
- controls = new HashMap<String, Variable2>();\r
- sketches = new ArrayList<Sketch2>();\r
- }\r
-\r
- public Model parse(File file) {\r
- try {\r
- // peek at the first line to see if we need to use UTF-8\r
- BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));\r
- String line = reader.readLine();\r
-\r
- if (line == null) {\r
- // file is empty, nothing to do here\r
- reader.close();\r
- return null;\r
- }\r
-\r
- if (line.startsWith(UTF_8)) {\r
- reader.close();\r
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));\r
- // skip the first line\r
- reader.readLine();\r
- line = reader.readLine();\r
- }\r
- \r
- // read variable data\r
- line = readVariables(reader, line);\r
- \r
- if (line == null) {\r
- // unexpected end of file\r
- System.err.println("unexpected end of file");\r
- reader.close();\r
- return null;\r
- }\r
- \r
- // read sketch data\r
- line = readSketches(reader, line);\r
- \r
- if (line == null) {\r
- // unexpected end of file\r
- System.err.println("unexpected end of file");\r
- reader.close();\r
- return null;\r
- }\r
- \r
- // read other data\r
- \r
- do {\r
- // ignore other data for now\r
- } while ((line = reader.readLine()) != null);\r
-\r
- reader.close();\r
- }\r
- catch (IOException e) {\r
- e.printStackTrace();\r
- return null;\r
- }\r
- \r
- // create new model\r
-\r
- Model2 model = new Model2(file.getName());\r
- \r
- int offset = 0;\r
- \r
- for (Sketch2 sketch : sketches) {\r
- // must keep track of which elements in the sketch correspond to \r
- // which elements in the model so connections can be constructed \r
- // accurately\r
- HashMap<SketchElement, Element2> elementMap = new HashMap<SketchElement, Element2>();\r
- \r
- for (SketchElement element : sketch.getElements()) {\r
- Element2 e = element.getWriteableElement(0, 0);\r
- //model.addElement(e);\r
- //elementMap.put(element, e);\r
- }\r
- \r
- for (SketchConnection connection : sketch.getConnections()) {\r
- Connection2 c = connection.getWriteableConnection();\r
- //model.addConnection(c);\r
- }\r
- \r
- offset += sketch.getWidth() + 100;\r
- }\r
- \r
- return null;\r
- }\r
- \r
- private String readVariables(BufferedReader reader, String line) \r
- throws IOException {\r
- \r
- String category = null;\r
- \r
- do {\r
- if (line.isEmpty()) {\r
- continue;\r
- }\r
- \r
- StringBuilder buffer = new StringBuilder(line);\r
- \r
- while ((line = reader.readLine()) != null) {\r
- if (line.endsWith("\\"))\r
- buffer.append(line.substring(0, line.length()-1));\r
- else\r
- buffer.append(line);\r
- \r
- if (line.endsWith("|"))\r
- break;\r
- }\r
- \r
- String str = buffer.toString();\r
- \r
- // TODO: must handle categories other than .Control\r
- \r
- Variable2 var = MdlUtils.getPossibleVariable(str, category);\r
- if (var != null) {\r
- variables.put(var.getName(), var);\r
- continue;\r
- }\r
- \r
- System.err.println("unrecognized variable "+str);\r
- \r
- } while ((line = reader.readLine()) != null && !line.startsWith(SKETCH_START));\r
- \r
- return line;\r
- }\r
- \r
- private String readSketches(BufferedReader reader, String line) \r
- throws IOException {\r
- \r
- Sketch2 sketch = null;\r
- \r
- do {\r
- if (line.startsWith(SKETCH_START)) {\r
- sketch = new Sketch2();\r
- sketches.add(sketch);\r
- continue;\r
- }\r
- else if (line.startsWith(SKETCH_VERSION)) {\r
- // version declaration, nothing to do here\r
- continue;\r
- }\r
- else if (line.startsWith("*")) {\r
- sketch.setName(line.substring(1));\r
- continue;\r
- }\r
- else if (line.startsWith("$")) {\r
- // font declaration, nothing to do here\r
- continue;\r
- }\r
- \r
- SketchConnection connection = MdlUtils.getPossibleSketchConnection(line);\r
- if (connection != null) {\r
- sketch.addSketchObject(connection);\r
- continue;\r
- }\r
- \r
- SketchVariable variable = MdlUtils.getPossibleSketchVariable(line, variables);\r
- if (variable != null) {\r
- sketch.addSketchObject(variable);\r
- continue;\r
- }\r
- \r
- SketchValve valve = MdlUtils.getPossibleSketchValve(line);\r
- if (valve != null) {\r
- // the next row after a valve should always the variable associated with the valve\r
- SketchVariable attached = MdlUtils.getPossibleSketchVariable(reader.readLine(), variables);\r
- if (attached == null || !attached.isAttached()) {\r
- // TODO: should also verify that the variable is in fact attached\r
- System.err.println("attached variable not found for valve");\r
- continue;\r
- }\r
- valve.setAttachedVariable(attached);\r
- sketch.addSketchObject(valve);\r
- sketch.addSketchObject(attached);\r
- continue;\r
- }\r
- \r
- SketchComment comment = MdlUtils.getPossibleSketchComment(line);\r
- if (comment != null) {\r
- if (comment.hasTextNextLine()) {\r
- comment.setText(reader.readLine());\r
- }\r
- \r
- if (comment.isIOElement()) {\r
- System.err.println("IO elements are not currently supported");\r
- continue;\r
- }\r
- \r
- sketch.addSketchObject(comment);\r
- continue;\r
- }\r
- \r
- // if we got this far, the element was not recognized\r
- System.err.println("unrecognized element "+line);\r
- \r
- } while ((line = reader.readLine()) != null && !line.startsWith(SKETCH_END));\r
- \r
- return line;\r
- }\r
-\r
-}\r
+++ /dev/null
-package org.simantics.sysdyn.mdlImport;\r
-\r
-import java.util.HashMap;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import org.simantics.sysdyn.mdlImport.model.SketchComment;\r
-import org.simantics.sysdyn.mdlImport.model.SketchConnection;\r
-import org.simantics.sysdyn.mdlImport.model.SketchElement;\r
-import org.simantics.sysdyn.mdlImport.model.SketchValve;\r
-import org.simantics.sysdyn.mdlImport.model.SketchVariable;\r
-import org.simantics.sysdyn.mdlImport.model.Variable2;\r
-import org.simantics.sysdyn.mdlImport.model.Valve2.TextPosition;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-public class MdlUtils {\r
- \r
- public enum ConnectionType {\r
- ARROW, LINE_ARROW, LINE_SEGMENT, OTHER\r
- }\r
- \r
- public enum CommentIcon {\r
- CLOUD, OTHER\r
- }\r
-\r
- // most of this data is from the documentation of the .mdl file format \r
- // available in http://www.vensim.com/documentation/24305.htm\r
-\r
- // a Vensim variable name is either a plain string that contains letters, \r
- // numbers and whitespace, or a quoted string that can also contain any \r
- // special characters (including other quotation marks that must be escaped)\r
- private static final String VAR_NAME_QUOTED =\r
- "\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"";\r
- private static final String VAR_NAME_SIMPLE =\r
- "[A-Za-z](?![ \\w]*\\()(?: *\\w+)*";\r
- private static final String VAR_NAME =\r
- "("+VAR_NAME_QUOTED+"|"+VAR_NAME_SIMPLE+")";\r
- \r
- private static final String SUBSCRIPT =\r
- "("+VAR_NAME_SIMPLE+")\\[("+VAR_NAME_SIMPLE+"(?:,"+VAR_NAME_SIMPLE+")*)\\]";\r
-\r
- // the first part of the variable string is the variable name \r
- // followed by a delimiter which depends on the type of the declaration\r
- private static final String VARIABLE_PATTERN =\r
- VAR_NAME+"\\s*=\\s*";\r
- private static final String SUBSCRIPT_PATTERN =\r
- SUBSCRIPT+"\\s*=\\s*";\r
- private static final String VALUE_NEW_PATTERN =\r
- VAR_NAME+"\\s*:\\s*";\r
- private static final String VALUE_EQUALS_PATTERN =\r
- VAR_NAME+"\\s*<->\\s*";\r
- \r
- // the second part is the equation followed by '~'\r
- private static final String EQUATION_PATTERN =\r
- "([^~]*?(?:"+VAR_NAME_QUOTED+"[^~]*?)*)\\s*~\\s*";\r
- \r
- // the third part is the unit followed by '~'\r
- private static final String UNIT_PATTERN =\r
- "([^~]*?)\\s*~\\s*";\r
- \r
- // the last part is the description followed by '|'\r
- private static final String DESC_PATTERN =\r
- "([^\\|]*?)\\s*\\|";\r
-\r
- public static final String variablePattern = \r
- VARIABLE_PATTERN+EQUATION_PATTERN+UNIT_PATTERN+DESC_PATTERN;\r
- public static final String subscriptPattern =\r
- SUBSCRIPT_PATTERN+EQUATION_PATTERN+UNIT_PATTERN+DESC_PATTERN;\r
- public static final String valueNewPattern = \r
- VALUE_NEW_PATTERN+EQUATION_PATTERN+UNIT_PATTERN+DESC_PATTERN;\r
- public static final String valueEqualsPattern = \r
- VALUE_EQUALS_PATTERN+EQUATION_PATTERN+UNIT_PATTERN+DESC_PATTERN;\r
- \r
- private static final int variableName = 1;\r
- private static final int variableEquation = 2;\r
- private static final int variableUnit = 3;\r
- private static final int variableDesc = 4;\r
- \r
- public static Variable2 getPossibleVariable(String line, String category) {\r
- Matcher matcher = Pattern.compile(variablePattern).matcher(line);\r
- \r
- if (!matcher.matches()) {\r
- return null;\r
- }\r
- \r
- String name = matcher.group(variableName);\r
- String equation = matcher.group(variableEquation);\r
- String unit = matcher.group(variableUnit);\r
- String description = matcher.group(variableDesc);\r
- \r
- return new Variable2(name, equation, unit, description);\r
- }\r
- \r
- public static Pair<String, String> getPossibleIntegral(String equation) {\r
- \r
- Matcher matcher = Pattern.compile("INTEG\\s*\\((.*),(.*)\\)").matcher(equation);\r
- if (matcher.matches()) {\r
- return new Pair<String, String>(matcher.group(1), matcher.group(2));\r
- }\r
- \r
- return null;\r
- }\r
- \r
- // sketch object data is defined similarly\r
- \r
- private static final String SAVE = "(-?\\d+),";\r
- private static final String SKIP = "-?\\d+,";\r
- private static final String POINTS = "(\\d+\\|(?:\\(-?\\d+,-?\\d+\\)\\|)+)";\r
- \r
- public static final String sketchConnection =\r
- // 1, id, from,to, shape,hid, pol, thick,hasf,dtype,res,color,font,np|plist\r
- "1,"+SAVE+SAVE+SAVE+SAVE+ SKIP+SKIP+SKIP+ SKIP+SKIP+ "0,-1--1--1,.*,"+POINTS;\r
- \r
- // group indices for later use\r
- private static final int connectionId = 1;\r
- private static final int connectionFrom = 2;\r
- private static final int connectionTo = 3;\r
- private static final int connectionShape = 4;\r
- private static final int connectionPoints = 5;\r
- \r
- private static final String COMMON =\r
- // x, y, w, h, sh, bits,hid, hasf,tpos,bw,nav1,nav2(,box,fill,font)\r
- SAVE+SAVE+SAVE+SAVE+SAVE+SAVE+SKIP+SKIP+SAVE+".*";\r
- \r
- public static final String sketchVariable =\r
- // n, id, name, x,y,w,h,sh,bits,hid,hasf,tpos,bw,nav1,nav2(,box,fill,font)\r
- "10,"+SAVE+VAR_NAME+","+COMMON;\r
- public static final String sketchValve =\r
- "11,"+SAVE+SAVE+ COMMON;\r
- public static final String sketchComment =\r
- "12,"+SAVE+SAVE+ COMMON;\r
- \r
- // group indices for later use\r
- private static final int elementId = 1;\r
- private static final int elementName = 2;\r
- private static final int elementX = 3;\r
- private static final int elementY = 4;\r
- private static final int elementWidth = 5;\r
- private static final int elementHeight = 6;\r
- private static final int elementShape = 7;\r
- private static final int elementBits = 8;\r
- private static final int elementTextPos = 9;\r
- \r
- public static SketchConnection getPossibleSketchConnection(String line) {\r
- Matcher matcher = Pattern.compile(sketchConnection).matcher(line);\r
- \r
- if (!matcher.matches()) {\r
- return null;\r
- }\r
- \r
- int id = Integer.parseInt(matcher.group(connectionId));\r
- int from = Integer.parseInt(matcher.group(connectionFrom));\r
- int to = Integer.parseInt(matcher.group(connectionTo));\r
- ConnectionType type = getConnectionType(matcher);\r
- \r
- return new SketchConnection(id, from, to, type);\r
- }\r
- \r
- public static SketchVariable getPossibleSketchVariable(String line, HashMap<String, Variable2> variables) {\r
- Matcher matcher = Pattern.compile(sketchVariable).matcher(line);\r
- \r
- if (!matcher.matches()) {\r
- return null;\r
- }\r
- \r
- int id = Integer.parseInt(matcher.group(elementId));\r
- Variable2 var = variables.get(matcher.group(elementName));\r
- boolean attached = elementIsAttached(matcher);\r
- boolean in = elementAllowsInBound(matcher);\r
- boolean out = elementAllowsOutBound(matcher);\r
- \r
- SketchVariable variable = new SketchVariable(id, var, attached, in, out);\r
- \r
- initializeElement(variable, matcher);\r
- \r
- return variable;\r
- }\r
- \r
- public static SketchValve getPossibleSketchValve(String line) {\r
- Matcher matcher = Pattern.compile(sketchValve).matcher(line);\r
- \r
- if (!matcher.matches()) {\r
- return null;\r
- }\r
- \r
- int id = Integer.parseInt(matcher.group(elementId));\r
- \r
- SketchValve valve = new SketchValve(id);\r
- \r
- initializeElement(valve, matcher);\r
- \r
- return valve;\r
- }\r
- \r
- public static SketchComment getPossibleSketchComment(String line) {\r
- Matcher matcher = Pattern.compile(sketchComment).matcher(line);\r
- \r
- if (!matcher.matches()) {\r
- return null;\r
- }\r
- \r
- int id = Integer.parseInt(matcher.group(elementId));\r
- CommentIcon icon = getCommentIcon(matcher);\r
- boolean nextLine = elementHasCommentLine(matcher);\r
- boolean isIO = elementIsIO(matcher);\r
- \r
- SketchComment comment = new SketchComment(id, icon, nextLine, isIO);\r
- \r
- initializeElement(comment, matcher);\r
- \r
- return comment;\r
- }\r
- \r
- public static void initializeElement(SketchElement element, Matcher matcher) {\r
- int x = Integer.parseInt(matcher.group(elementX));\r
- int y = Integer.parseInt(matcher.group(elementY));\r
- int w = Integer.parseInt(matcher.group(elementWidth));\r
- int h = Integer.parseInt(matcher.group(elementHeight));\r
- \r
- element.setLocationAndSize(x, y, w, h);\r
- }\r
- \r
- public static ConnectionType getConnectionType(Matcher matcher) {\r
- switch(Integer.parseInt(matcher.group(connectionShape))) {\r
- case 0: return ConnectionType.ARROW;\r
- case 4: return ConnectionType.LINE_ARROW;\r
- case 100: return ConnectionType.LINE_SEGMENT;\r
- default: return ConnectionType.OTHER;\r
- }\r
- }\r
- \r
- public static CommentIcon getCommentIcon(Matcher matcher) {\r
- switch(Integer.parseInt(matcher.group(elementName))) {\r
- case 48: return CommentIcon.CLOUD;\r
- default: return CommentIcon.OTHER;\r
- }\r
- }\r
- \r
- public static TextPosition getTextPos(Matcher matcher) {\r
- switch (Integer.parseInt(matcher.group(elementTextPos))) {\r
- case 0: return TextPosition.INSIDE;\r
- case 1: return TextPosition.BELOW;\r
- case 2: return TextPosition.LEFT;\r
- case 3: return TextPosition.ABOVE;\r
- case 4: return TextPosition.RIGHT;\r
- default: return TextPosition.UNSET;\r
- }\r
- }\r
- \r
- public static boolean elementIsAttached(Matcher matcher) {\r
- return (Integer.parseInt(matcher.group(elementShape)) & 1<<5) != 0;\r
- }\r
- \r
- public static boolean elementAllowsInBound(Matcher matcher) {\r
- return (Integer.parseInt(matcher.group(elementBits)) & 1) != 0;\r
- }\r
- \r
- public static boolean elementAllowsOutBound(Matcher matcher) {\r
- return (Integer.parseInt(matcher.group(elementBits)) & 1<<1) != 0;\r
- }\r
- \r
- public static boolean elementHasCommentLine(Matcher matcher) {\r
- return (Integer.parseInt(matcher.group(elementBits)) & 1<<2) != 0;\r
- }\r
- \r
- public static boolean elementIsIO(Matcher matcher) {\r
- return (Integer.parseInt(matcher.group(elementBits)) & 1<<3) != 0;\r
- }\r
- \r
- public static String normalize(String str) {\r
- // start by removing all tabs from the string, not really necessary \r
- // but does make the equation cleaner (could also be done in the read \r
- // method above)\r
- str = str.replaceAll("\t", "");\r
-\r
- // remove inline :AND: and :OR: etc (not done currently)\r
-\r
- // transform all variable names to (single-)quoted modelica syntax\r
- StringBuilder result = new StringBuilder();\r
- int offset = 0;\r
-\r
- Matcher matcher = Pattern.compile(VAR_NAME).matcher(str);\r
- while (matcher.find()) {\r
- result.append(str.substring(offset, matcher.start()));\r
-\r
- String replacement = matcher.group();\r
-\r
- if (replacement.startsWith("\"")) {\r
- replacement = replacement.substring(1, replacement.length() - 1);\r
- }\r
-\r
- result.append('\'');\r
- result.append(replacement);\r
- result.append('\'');\r
-\r
- offset = matcher.end();\r
- }\r
- if (offset < str.length()) {\r
- result.append(str.substring(offset));\r
- }\r
-\r
- str = result.toString();\r
-\r
- return str;\r
- }\r
- \r
-}\r