From f7fbf121aea62a519755dbba1e07e35e5e4c8b71 Mon Sep 17 00:00:00 2001 From: jkauttio Date: Fri, 14 Feb 2014 13:36:53 +0000 Subject: [PATCH] initial version of new vensim import (does not work) refs #2924 git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/branches/dev-jkauttio@28850 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.sysdyn.ui/plugin.xml | 5 + .../ui/handlers/imports/ImportMdlHandler.java | 2 +- .../simantics/sysdyn/mdlImport/MdlFile.java | 60 +- .../simantics/sysdyn/mdlImport/MdlParser.java | 535 ++++++++++++++---- .../simantics/sysdyn/mdlImport/MdlUtils.java | 45 ++ .../mdlImport/mdlElements/Expression.java | 3 +- .../sysdyn/mdlImport/mdlElements/View.java | 13 +- 7 files changed, 515 insertions(+), 148 deletions(-) create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlUtils.java diff --git a/org.simantics.sysdyn.ui/plugin.xml b/org.simantics.sysdyn.ui/plugin.xml index e90bae08..4d0dfc24 100644 --- a/org.simantics.sysdyn.ui/plugin.xml +++ b/org.simantics.sysdyn.ui/plugin.xml @@ -1139,6 +1139,11 @@ checkEnabled="true"> + + variables = new ArrayList(); - private ArrayList controls = new ArrayList(); - private ArrayList sketchData = new ArrayList(); - private ArrayList otherData = new ArrayList(); - - - public void addVariable(String variable) { - variables.add(variable); - } + private ArrayList variableData; + private ArrayList controlData; + private ArrayList otherData; + private ArrayList> sketchData; + private ArrayList currentSketch; - public ArrayList getVariables() { - return variables; + public MdlFile() { + variableData = new ArrayList(); + controlData = new ArrayList(); + otherData = new ArrayList(); + sketchData = new ArrayList>(); } - - public void addControl(String control) { - controls.add(control); + + public void addVariableData(String line) { + variableData.add(line); } - - public ArrayList getControls() { - return controls; + + public ArrayList getVariableData() { + return variableData; } - - public void addSketchData(String sketchRow) { - sketchData.add(sketchRow); + + public void addControlData(String line) { + controlData.add(line); } - public ArrayList getSketchData() { - return sketchData; + public ArrayList getControlData() { + return controlData; } - public void addOtherData(String dataRow) { - otherData.add(dataRow); + public void addOtherData(String line) { + otherData.add(line); } public ArrayList getOtherData() { return otherData; } + + public void startSketch() { + currentSketch = new ArrayList(); + sketchData.add(currentSketch); + } + public void addSketchData(String line) { + currentSketch.add(line); + } + + public ArrayList> getSketchData() { + return sketchData; + } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlParser.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlParser.java index 2f68f086..207d286f 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlParser.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlParser.java @@ -21,6 +21,8 @@ import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.simantics.sysdyn.mdlImport.mdlElements.Auxiliary; import org.simantics.sysdyn.mdlImport.mdlElements.Cloud; @@ -38,58 +40,354 @@ import org.simantics.sysdyn.mdlImport.mdlElements.Valve; import org.simantics.sysdyn.mdlImport.mdlElements.Variable; import org.simantics.sysdyn.mdlImport.mdlElements.View; +/* + * THINGS TO FIX: + * - vensim apparently supports infix operators (:AND: instead of AND()), these must be handled + * - "public" seems to be a keyboard of some sort which causes a problem in certain variable names + * - something is seriously wrong with the sketch import + * - how should models with multiple sketches be handled (this might already work) + * - instead of splitting the file into blocks, the parser could already process the data further which would greatly simplify later methods + */ + public class MdlParser { - + + private enum State { + VARIABLE, CONTROL, SKETCH, OTHER + } + public static Model parse(File file) { - + Model model = new Model(); - + String[] name = file.getName().split("\\.mdl"); model.setName(name[0]); + + MdlFile mdlFile = getMdlFile(file); + + for (String variable : mdlFile.getVariableData()) { + parseElement(variable); + } + + for (ArrayList sketch : mdlFile.getSketchData()) { + parseSketch(sketch); + } + + //MdlFile test = getMdlContents(file); + + //getVariableData(model, test.getVariableData()); + + //getSketchData(model, mdlFile.getSketchData()); + + //getControlData(model, mdlFile.getControlData()); + + //getOthertData(model, mdlFile.getOtherData()); + + //setAllSubscripts(model); + + return null; + } + + private static final String UTF_8 = "{UTF-8}"; + private static final String CONTROL_STR = ".Control"; + private static final String SKETCH_START = "\\\\\\---///"; + private static final String SKETCH_END = "///---\\\\\\"; + + private static MdlFile getMdlFile(File file) { + MdlFile mdl = new MdlFile(); + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + String line = reader.readLine(); + + if (line != null && line.startsWith(UTF_8)) { + reader.close(); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); + // skip the "{UTF-8}" line + reader.readLine(); + line = reader.readLine(); + } + + State state = State.VARIABLE; + + while (line != null) { + line = line.trim(); + + if (line.isEmpty()) { + line = reader.readLine(); + continue; + } + + switch (state) { + case VARIABLE: + if (line.startsWith(SKETCH_START)) { + state = State.SKETCH; + continue; + } + + String variable = readElement(reader, line); + + if (variable.contains(CONTROL_STR)) { + state = State.CONTROL; + break; + } + + mdl.addVariableData(variable); + break; + + case CONTROL: + if (line.startsWith(SKETCH_START)) { + state = State.SKETCH; + continue; + } + + String control = readElement(reader, line); + mdl.addControlData(control); + break; + + + case SKETCH: + if (line.startsWith(SKETCH_END)) { + state = State.OTHER; + break; + } + + if (line.startsWith(SKETCH_START)) { + mdl.startSketch(); + break; + } + + mdl.addSketchData(line); + break; + + case OTHER: + mdl.addOtherData(line); + break; + + default: break; // should not get this far + } + + line = reader.readLine(); + } + + reader.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + + return mdl; + } + + private static String readElement(BufferedReader reader, String current) + throws IOException { + // TODO: does not support subscript stuff at all currently + StringBuilder element = new StringBuilder(); + + while (current != null) { + current = current.trim().replace('\t', ' '); + + if (current.endsWith("|")) { + element.append(current.substring(0, current.length() - 1)); + break; + } + else if (current.endsWith("\\")) { + element.append(current.substring(0, current.length() - 1)); + } + else { + element.append(current); + } + + current = reader.readLine(); + } + + return element.toString(); + } + + private static void parseElement(String element) { + String left, right, unit, desc; + + String[] data = element.split("~"); + + if (data.length != 3) { + System.err.println("INVALID ELEMENT DATA "+element); + return; + } + + String equation = sanitize(data[0]); + + left = equation.substring(0, equation.indexOf('=')).trim(); + right = equation.substring(equation.indexOf('=') + 1).trim(); + unit = data[1].trim(); + desc = data[2].trim(); + + //System.err.println("FOUND VARIABLE "+left); + //System.err.println(" EQUATION "+right); + //System.err.println(" UNIT "+unit); + //System.err.println(" DESC "+desc); + + } + + // matches a quoted string that may contain escaped special characters + // (which includes other quotation marks) + private static final String QUOTED_PATTERN = "\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\""; + // matches (possibly escaped) unsupported characters + private static final String BADCHARS_PATTERN = "\\\\?[-+*/()=<>\"]"; + // matches a substring that should be capitalized (see below for details) + private static final String NAMEPART_PATTERN = "([A-Za-z])[A-Za-z]*"; + + private static String sanitize(String str) { + //TODO: fix this to produce quoted modelica strings instead + StringBuilder result = new StringBuilder(str); + + Matcher matcher; + + matcher = Pattern.compile(QUOTED_PATTERN).matcher(str); + while (matcher.find()) { + // TODO: could do something more clever than just an underscore + String replacement = Pattern.compile(BADCHARS_PATTERN).matcher(matcher.group(1)).replaceAll("_"); + result.replace(matcher.start(), matcher.end(), replacement); + } + + // also capitalize all variable names to remove certain openmodelica + // keywords such as "public" or "private", this might not seem like + // the most sane variable name handling scheme possible, but it is + // nevertheless the one we are forced to use + matcher = Pattern.compile(NAMEPART_PATTERN).matcher(result.toString()); + while (matcher.find()) { + // replace the first character of the match with the same + // character in upper case + result.replace(matcher.start(1), matcher.end(1), matcher.group(1).toUpperCase()); + } + + return result.toString(); + } + + private static void parseSketch(ArrayList sketch) { + // the sketch should have at least three lines, version, name and font + if (sketch.size() < 3 || + !sketch.get(0).startsWith("V300") || + !sketch.get(1).startsWith("*") || + !sketch.get(2).startsWith("$")) { + System.err.println("INVALID SKETCH DATA"); + return; + } + + // parse name + String name = sketch.get(1).substring(1); + // parse font + String font = sketch.get(2).substring(2); + + for (int i = 3; i < sketch.size(); i++) { + String line = sketch.get(i); + if (line.startsWith(CONNECTION_PREFIX)) { + parseConnection(line.substring(2)); + } + else if (line.startsWith(VARIABLE_PREFIX)) { + parseVariable(line.substring(3)); + } + else if (line.startsWith(VALVE_PREFIX)) { + //parseValve(line.substring(3)); + } + else if (line.startsWith(COMMENT_PREFIX)) { + //parseComment(line.substring(3)); + } + else { + //System.err.println("UNSUPPORTED SKETCH OBJECT "+line); + } + } + } + + // these methods are implemented according to the documentation on the .mdl + // file format available in http://www.vensim.com/documentation/24305.htm + + // (1,)id,from,to,shape,hid,pol,thick,hasf,dtype,res,color,font,np|plist + private static final String CONNECTION_PREFIX = "1,"; + private static final String CONNECTION_PATTERN = + "(\\d+),(\\d+),(\\d+).*"; + // (n,)id,name,x,y,w,h,sh,bits,hid,hasf,tpos,bw,nav1,nav2(,box,fill,font) + private static final String VARIABLE_PREFIX = "10,"; + private static final String VALVE_PREFIX = "11,"; + private static final String COMMENT_PREFIX = "12,"; + private static final String ELEMENT_PATTERN = + "(\\d+),(\".*\"|[^\",]*),(-?\\d+),(-?\\d+),(\\d+),(\\d+).*"; + + private static void parseConnection(String line) { + Matcher matcher = Pattern.compile(CONNECTION_PATTERN).matcher(line); + if (!matcher.matches()) { + System.err.println("MALFORMED CONNECTION"); + return; + } + + // the fields of interest are: id, from, to, ... (TODO) + int id = Integer.parseInt(matcher.group(1)); + int from = Integer.parseInt(matcher.group(2)); + int to = Integer.parseInt(matcher.group(3)); + + System.err.println("connection "+id+": "+from+" -> "+to); + } + + private static void parseVariable(String line) { + Matcher matcher = Pattern.compile(ELEMENT_PATTERN).matcher(line); + if (!matcher.matches()) { + System.err.println("MALFORMED VARIABLE "+line); + return; + } - MdlFile mdlFile = getMdlContents(file); - - getVariableData(model, mdlFile.getVariables()); - - getSketchData(model, mdlFile.getSketchData()); - - getControlData(model, mdlFile.getControls()); + int id = Integer.parseInt(matcher.group(1)); + String name = sanitize(matcher.group(2)); + int x = Integer.parseInt(matcher.group(3)); + int y = Integer.parseInt(matcher.group(4)); + int width = Integer.parseInt(matcher.group(5)); + int height = Integer.parseInt(matcher.group(6)); -// getOthertData(model, mdlFile.getOtherData()); + System.err.println("variable "+id+": "+name+" ("+x+","+y+")"); + } + + private static void parseValve(String line) { - setAllSubscripts(model); + } + + private static void parseComment(String line) { - return model; } - + + + + + + + + + private static MdlFile getMdlContents(File aFile) { MdlFile mdlFile = new MdlFile(); - + try { BufferedReader input = new BufferedReader(new FileReader(aFile)); - + try { - String line = null; //not declared within while loop + String line = null; // not declared within while loop + mdlFile.startSketch(); + // See if the document is encoded with UTF-8. It will be marked with {UTF-8} on the first line input.mark(30); - if (( line = input.readLine()) != null && - line.contains("{UTF-8}")){ + if ((line = input.readLine()) != null && line.contains("{UTF-8}")){ Reader in = new InputStreamReader(new FileInputStream(aFile), "UTF-8"); input = new BufferedReader(in); line = input.readLine(); } else { input.reset(); } - - + + boolean isControl = false; - - while (( line = input.readLine()) != null){ + + while ((line = input.readLine()) != null) { // Build an element (combine the lines to one string) StringBuilder elementBuilder = new StringBuilder(); - while(line != null && !line.contains("\\\\\\---///")) { + while (line != null && !line.contains("\\\\\\---///")) { // Add a new line for the element elementBuilder.append(line); if(line.endsWith("|") && !line.endsWith("~~|")) { @@ -98,13 +396,13 @@ public class MdlParser { } line = input.readLine(); } - - if(line.contains("\\\\\\---///")) + + if (line.contains("\\\\\\---///")) break; - + String variable = elementBuilder.toString(); - if(variable.trim().matches("[\\*]{46}.+[\\*]{46}.+")) { + if (variable.trim().matches("[\\*]{46}.+[\\*]{46}.+")) { if(variable.contains(".Control")) { isControl = true; } else { @@ -115,17 +413,17 @@ public class MdlParser { // Add element string to model if(isControl) { - mdlFile.addControl(variable); + mdlFile.addControlData(variable); } else { - mdlFile.addVariable(variable); + mdlFile.addVariableData(variable); } } - - while (( line = input.readLine()) != null && !line.contains("///---\\\\\\")){ + + while ((line = input.readLine()) != null && !line.contains("///---\\\\\\")) { mdlFile.addSketchData(line); } - - while (( line = input.readLine()) != null){ + + while ((line = input.readLine()) != null){ mdlFile.addOtherData(line); } } @@ -136,10 +434,10 @@ public class MdlParser { catch (IOException ex){ ex.printStackTrace(); } - + return mdlFile; } - + private static void getVariableData(Model model, ArrayList elements) { ArrayList equivalenceSubscripts = new ArrayList(); for(String elementString : elements) { @@ -148,7 +446,7 @@ public class MdlParser { equivalenceSubscripts.add((EquivalenceSubscript) v); } } - + // All variables are ready, determine subscript equivalences for(EquivalenceSubscript es : equivalenceSubscripts) { Element e = model.getElement(es.getEquivalentToName()); @@ -157,13 +455,13 @@ public class MdlParser { } } } - - + + private static void getControlData(Model model, ArrayList controls) { for(String controlString : controls) { String[] nameAndData = controlString.split("="); String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); - + if(nameAndData[0].trim().equals("FINAL TIME")) { model.setEndTime(Double.parseDouble(expressionUnitsAndComments[0])); } else if(nameAndData[0].trim().equals("INITIAL TIME")) { @@ -175,9 +473,9 @@ public class MdlParser { model.setTimeUnit(expressionUnitsAndComments[1]); } } - + } - + private static Variable getVariable(Model model, String name) { Element e = model.getElement(name); Variable variable = null; @@ -185,7 +483,7 @@ public class MdlParser { variable = (Variable)e; return variable; } - + private static String[] getNormalVariableNameDataAndRange(String element) { String[] nameAndData = element.split("=", 2); String[] nameAndRange = nameAndData[0].trim().split("[\\[|\\]]"); @@ -193,21 +491,21 @@ public class MdlParser { return new String[] {nameAndRange[0], nameAndData[1], nameAndRange.length == 2 ? nameAndRange[1] : null}; return null; } - + private static String[] getSubscriptNameAndData(String element) { String[] nameAndData = element.split(":"); if(nameAndData.length == 2) return nameAndData; return null; } - + private static String[] getEquivalenceSubscriptNameAndData(String element) { String[] nameAndData = element.split("\\<\\-\\>"); if(nameAndData.length == 2) return nameAndData; return null; } - + private static String[] getTableNameDataAndRange(String element) { String[] parts = element.split("\\~"); if(!parts[0].contains("(") || !parts[0].contains(")")) @@ -220,33 +518,37 @@ public class MdlParser { return new String[] {nameAndRange[0], nameAndData[1], nameAndRange.length == 2 ? nameAndRange[1] : null}; return nameAndData; } - + private static String[] getDataVariableNameAndData(String element) { String[] nameAndData = { element.substring(0, element.indexOf("~")), " " + element.substring(element.indexOf("~"))}; return nameAndData; } - + private static Variable createVariable(Model model, String elementString) { String[] elementExpressions = elementString.split("\\~\\~\\|"); - + Variable variable = null; + System.err.println("CREATE VARIABLE "+elementString); + for(String s : elementExpressions) { + System.err.println(" INSIDE FOR"); + // Skip these definitions at least for now if(elementExpressions.length > 1 && s.contains("A FUNCTION OF")) continue; - + Expression expression = new Expression(); String[] nameAndData = null; String name; - + // Create the expression based on the expression string if((nameAndData = getNormalVariableNameDataAndRange(s)) != null) { - + name = nameAndData[0].replace("\"", ""); variable = getVariable(model, name); if(variable == null) { @@ -254,7 +556,7 @@ public class MdlParser { variable.setName(name); model.addElement(variable); } - + if(!nameAndData[1].trim().endsWith("|")) { // Multiple expressions expression.setExpression(nameAndData[1].trim()); @@ -262,9 +564,9 @@ public class MdlParser { String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); expression.setExpression(expressionUnitsAndComments[0].trim()); } - + } else if((nameAndData = getSubscriptNameAndData(s)) != null) { - + name = nameAndData[0].replace("\"", ""); variable = getVariable(model, name); if(variable == null) { @@ -272,15 +574,15 @@ public class MdlParser { variable.setName(name); model.addElement(variable); } - + // No support for multidimensional variables. Don't know what that would mean String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); expression.setExpression(expressionUnitsAndComments[0].trim()); variable.setUnits(expressionUnitsAndComments[1].trim()); variable.setComments(expressionUnitsAndComments[2].trim()); - + } else if((nameAndData = getEquivalenceSubscriptNameAndData(s)) != null) { - + name = nameAndData[0].replace("\"", ""); variable = getVariable(model, name); if(variable == null) { @@ -288,15 +590,15 @@ public class MdlParser { variable.setName(name); model.addElement(variable); } - + // No support for multidimensional variables. Don't know what that would mean String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); expression.setExpression(expressionUnitsAndComments[0].trim()); variable.setUnits(expressionUnitsAndComments[1].trim()); variable.setComments(expressionUnitsAndComments[2].trim()); - + } else if((nameAndData = getTableNameDataAndRange(s)) != null) { - + name =(nameAndData[0].replace("\"", "")); variable = getVariable(model, name); if(variable == null) { @@ -304,7 +606,7 @@ public class MdlParser { variable.setName(name); model.addElement(variable); } - + String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); // ([(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) String table = expressionUnitsAndComments[0].trim().split("[\\[|\\]]")[2]; @@ -314,10 +616,10 @@ public class MdlParser { table = table.replace("(", "{"); table = table.replace(")", "}"); expression.setExpression(table); - - + + } else if((nameAndData = getDataVariableNameAndData(s)) != null) { - + name = nameAndData[0].replace("\"", ""); variable = getVariable(model, name); if(variable == null) { @@ -325,17 +627,17 @@ public class MdlParser { variable.setName(name); model.addElement(variable); } - + expression.setExpression(""); } - + if(nameAndData == null || variable == null) continue; - + // Set possible range for the expression if(nameAndData.length == 3) expression.setRange(nameAndData[2]); - + // Set units and comments for the variable if(nameAndData[1].trim().endsWith("|")) { String[] expressionUnitsAndComments = nameAndData[1].split("[\\~|\\|]"); @@ -348,7 +650,7 @@ public class MdlParser { units.lastIndexOf("[") + 1, units.length() - 1); String[] rangeParts = range.split(","); - + try { variable.setRangeStart(Double.parseDouble(rangeParts[0])); if(rangeParts.length >= 2) @@ -363,25 +665,27 @@ public class MdlParser { variable.setUnits(expressionUnitsAndComments[1].trim()); variable.setComments(expressionUnitsAndComments[2].trim()); } - + // Finally add the expression to element variable.getExpressions().add(expression); } return variable; } - + private static int SCALE = 4; - private static void getSketchData(Model model, ArrayList sketchData) { + private static void getSketchData(Model model, ArrayList sketchData) { String line = null; View view = null; + int i = 0; + while(i < sketchData.size()) { line = sketchData.get(i); if(line.startsWith("*")) { view = new View(); model.addView(view); - + view.setName(line.substring(1)); // STARTED A NEW VIEW @@ -390,26 +694,26 @@ public class MdlParser { ArrayList ghostNumbers = new ArrayList(); ArrayList connections = new ArrayList(); HashMap emptyValves = new HashMap(); // map for valves that don't have an element - - + + i++; line = sketchData.get(i); while(i < sketchData.size() && !sketchData.get(i).startsWith("*")) { line = sketchData.get(i); - + if(line.startsWith("$")) { view.setFontParameters(line); i++; continue; } - + String[] data = line.split(","); - if(data[0].equals("1")) { + if (data[0].equals("1")) { // Connections are handled after all elements String[] connectionData = line.split(","); connections.add(connectionData); - - } else if(data[0].equals("11")){ + + } else if (data[0].equals("11")){ // Valve i = i + 1; String elementLine = sketchData.get(i); @@ -417,7 +721,7 @@ public class MdlParser { // FIXME: Assumes that element is always attached to the valve Element element = model.getElement(elementData[2].replace("\"", "")); Valve valve = new Valve(); - if(element != null && element instanceof Variable) { + if (element != null && element instanceof Variable) { Variable v = (Variable) element; valve.setName(v.getName()); valve.setExpressions(v.getExpressions()); @@ -425,10 +729,10 @@ public class MdlParser { valve.setComments(v.getComments()); valve.setX(Integer.parseInt(data[3]) / SCALE); valve.setY(Integer.parseInt(data[4]) / SCALE); - + model.removeElement(element); model.addElement(view, valve); - + // Add valve to the element list with both valve and variable symbol numbers elementNumbers.put(elementData[1], valve); elementNumbers.put(data[1], valve); @@ -436,19 +740,20 @@ public class MdlParser { i = i - 1; emptyValves.put(data[1], data); } - } else if(data[0].equals("12")){ + } else if (data[0].equals("12")){ // Cloud Cloud cloud = new Cloud(); cloud.setX(Integer.parseInt(data[3]) / SCALE); cloud.setY(Integer.parseInt(data[4]) / SCALE); elementNumbers.put(data[1], cloud); model.addElement(view, cloud); - } else if(data[0].equals("10") && data.length <= 15){ + } else if (data[0].equals("10") && data.length <= 15){ // Some variable Element e = model.getElement(data[2].replace("\"", "").trim()); - if(e != null && e instanceof Variable) { + + if (e != null && e instanceof Variable) { Variable v = (Variable) e; - if(v.getExpressions().get(0).getExpression().startsWith("INTEG (") && !(e instanceof Stock)) { + if (v.getExpressions().get(0).getExpression().startsWith("INTEG (") && !(e instanceof Stock)) { // Stock Stock s = new Stock(); s.setName(v.getName()); @@ -465,7 +770,7 @@ public class MdlParser { e.setY(Integer.parseInt(data[4]) / SCALE); elementNumbers.put(data[1], e); model.relocateElement(view, e); - } else if(data[0].equals("10") && data.length > 15){ + } else if (data[0].equals("10") && data.length > 15){ // TODO: Ghost // for now, direct back to the original element Element originalElement = model.getElement(data[2].replace("\"", "")); @@ -474,45 +779,46 @@ public class MdlParser { ghostNumbers.add(data[1]); } } - + i++; } + i--; - + // Find the first variable that is connected to an empty valve for(String[] connectionData : connections) { if(!connectionData[9].equals("64")) continue; // not dependency String[] end = emptyValves.get(connectionData[3]); - if(end != null && elementNumbers.get(connectionData[3]) == null) { + if (end != null && elementNumbers.get(connectionData[3]) == null) { // Use the connected element to create a valve and give it a name Element start = elementNumbers.get(connectionData[2]); - if(start == null) + if (start == null) continue; - + Valve valve = new Valve(); valve.setName(start.getName() + " Rate"); valve.setX(Integer.parseInt(end[3]) / SCALE); valve.setY(Integer.parseInt(end[4]) / SCALE); - + model.addElement(view, valve); elementNumbers.put(connectionData[3], valve); valve.setUnits(""); valve.setComments(""); } } - - - + + + for(String[] connectionData : connections) { - + Element start = elementNumbers.get(connectionData[2]); Element end = elementNumbers.get(connectionData[3]); // Discard connection if one of the ends is null if(start == null || end == null) continue; - - + + Connection connection; if(connectionData[9].equals("64")) { // Dependency @@ -521,7 +827,7 @@ public class MdlParser { String controlX = connectionData[13].substring(connectionData[13].indexOf("(") + 1); String controlY = connectionData[14].substring(0, connectionData[14].indexOf(")")); Point2D controlPoint = new Point2D.Double(Double.parseDouble(controlX) / SCALE, Double.parseDouble(controlY) / SCALE); - + if(ghostNumbers.contains(connectionData[2]) || ghostNumbers.contains(connectionData[3])) { connection = new Dependency(); @@ -533,7 +839,7 @@ public class MdlParser { connection = new Dependency(angle); } - + } else { // Flow connection = new Flow(); @@ -548,8 +854,8 @@ public class MdlParser { connection.setEnd(end); model.addConnection(connection); } - - + + // Generate expressions for empty valves for(String key : emptyValves.keySet()) { Element e = elementNumbers.get(key); @@ -566,14 +872,14 @@ public class MdlParser { break; } } - + // Create the expression. Use the expression of the stock, and undo the effect of other valves if(stock != null && stock instanceof Stock) { Expression expression = new Expression(); - + StringBuilder sb = new StringBuilder(); sb.append(((Stock)stock).getIntegralParts(stock.getExpressions().get(0))[0]); - + for(Connection c : stock.getConnections()) { if(c instanceof Flow) { if(c.getStart().equals(stock) && !c.getEnd().equals(valve)) { @@ -593,24 +899,25 @@ public class MdlParser { } } } + i++; } } - + private static void getOthertData(Model model, String otherData) { - + } - + private static void setAllSubscripts(Model model) { - + // Set subscripts for all elements ArrayList elements = new ArrayList(); elements.addAll(model.getUnlocatedElements()); for(View view : model.getViews()) { elements.addAll(view.getElements()); } - + for(Element e : elements) { if(!(e instanceof Variable)) continue; @@ -618,5 +925,5 @@ public class MdlParser { v.initializeSubscripts(model); } } - + } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlUtils.java new file mode 100644 index 00000000..e5505a6a --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/MdlUtils.java @@ -0,0 +1,45 @@ +package org.simantics.sysdyn.mdlImport; + +import java.util.regex.Pattern; + +public class MdlUtils { + + /* + * the utils in this file are written based on the documentation of .mdl + * file format available in http://www.vensim.com/documentation/24305.htm + */ + + public static void parseSketchObject(String line) { + // 1,id,from,to,shape,hid,pol,thick,hasf,dtype,res,color,font,np|plist + + // the specification also contains "box,fill,font" at the end of the + // pattern but it does not seem to appear in any of our models + // so that is probably optional (or not used if the font is defined) + + // n,id,name,x,y,w,h,sh,bits,hid,hasf,tpos,bw,nav1,nav2(,box,fill,font) + + String type = line.substring(0, line.indexOf(',')); + + if (type.equals("1")) { + // a connection + parseConnection(line); + } + else if (type.equals("10") || type.equals("11") || type.equals("12")) { + // an element + parseElement(line); + } + else { + // not supported + } + } + + private static void parseConnection(String line) { + // 1,id,from,to,shape,hid,pol,thick,hasf,dtype,res,color,font,np|plist + + } + + private static void parseElement(String line) { + // n,id,name,x,y,w,h,sh,bits,hid,hasf,tpos,bw,nav1,nav2(,box,fill,font) + } + +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/Expression.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/Expression.java index e36ca60a..adff3bab 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/Expression.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/Expression.java @@ -13,6 +13,7 @@ package org.simantics.sysdyn.mdlImport.mdlElements; public class Expression { + private String range, expression; @Override @@ -29,7 +30,7 @@ public class Expression { } public String getExpression() { - if(expression == null) + if (expression == null) return ""; return expression; } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/View.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/View.java index 88fe41e6..89fcc203 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/View.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/mdlImport/mdlElements/View.java @@ -23,7 +23,6 @@ public class View implements IWriteableMDLObject { private String name, fontParameters; private ArrayList elements = new ArrayList(); - @Override public void write(WriteGraph graph, Resource parent) { @@ -35,18 +34,18 @@ public class View implements IWriteableMDLObject { } public void addElement(Element e) { - if(e instanceof Subscript || - e instanceof Function) + if (e instanceof Subscript || e instanceof Function) return; - if(e.getX()maxX) + if (e.getX() > maxX) maxX = e.getX(); - if(e.getY()maxY) + if (e.getY() > maxY) maxY = e.getY(); + this.elements.add(e); } -- 2.47.1