/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.tools; import java.text.DecimalFormatSymbols; import java.util.List; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.numerics.MultiVarFunction; import org.opensourcephysics.numerics.ParsedMultiVarFunction; import org.opensourcephysics.numerics.ParserException; /** * This represents a parameter expression that is parsed and * evaluated as a function of other parameters. * * * @author Douglas Brown */ public class Parameter { final String paramName; // name of this parameter final String expression; // Suryono parser expression String description; // optional description of this parameter double value = Double.NaN; // current value of this parameter boolean expressionEditable = true; boolean nameEditable = true; /** * Constructor with name and function. * * @param name the name * @param function the function (parser expression) */ public Parameter(String name, String function) { paramName = name; expression = function; } /** * Constructor with name, function and description. * * @param name the name * @param function the function (parser expression) * @param desc the description */ public Parameter(String name, String function, String desc) { this(name, function); setDescription(desc); } /** * Gets the name of this parameter. * * @return the name */ public String getName() { return paramName; } /** * Gets the expression for this parameter. * * @return the expression */ public String getExpression() { return expression; } /** * Gets the description of this parameter. May return null. * * @return the description */ public String getDescription() { return description; } /** * Sets the description of this parameter. * * @param desc the description */ public void setDescription(String desc) { description = desc; } /** * Gets the current value of this parameter. * * @return the value (may be NaN) */ public double getValue() { return value; } /** * Returns true if this parameter's expression is user-editable. * * @return true if editable */ public boolean isExpressionEditable() { return expressionEditable; } /** * Sets the expression editable property. * * @param edit true if editable */ public void setExpressionEditable(boolean edit) { expressionEditable = edit; } /** * Returns true if this parameter's name is user-editable. * * @return true if editable */ public boolean isNameEditable() { return nameEditable; } /** * Sets the name editable property. * * @param edit true if editable */ public void setNameEditable(boolean edit) { nameEditable = edit; } /** * Determines if this is equal to another parameter. * * @param obj another object * @return true if equal */ public boolean equals(Object obj) { if(obj instanceof Parameter) { Parameter p = (Parameter) obj; return p.getName().equals(paramName)&&p.getExpression().equals(expression)&&(p.isExpressionEditable()==expressionEditable)&&(p.isNameEditable()==nameEditable); } return false; } /** * Determines the value of this parameter based on input parameter values. * * @param parameters the input parameters * @return the value (may be NaN) */ protected double evaluate(List<?> parameters) { int n = parameters.contains(this) ? parameters.size()-1 : parameters.size(); Parameter[] array = new Parameter[n]; int j = 0; for(int i = 0; i<parameters.size(); i++) { Parameter next = (Parameter) parameters.get(i); if(next==this) { continue; } array[j++] = next; } return evaluate(array); } /** * Determines the value of this parameter based on input parameter values. * This method assumes the array of parameters does not include this. * * @param parameters the input parameters * @return the value (may be NaN) */ public double evaluate(Parameter[] parameters) { int n = parameters.length; String[] names = new String[n]; double[] values = new double[n]; for(int i = 0; i<n; i++) { names[i] = parameters[i].paramName; values[i] = parameters[i].value; } try { String express = expression; // Suryono parser accepts only periods as decimal separators // check default locale separator and substitute period if needed DecimalFormatSymbols symbols = FunctionEditor.sciFormat.getDecimalFormatSymbols(); char separator = symbols.getDecimalSeparator(); // don't make substitutions in "if" statements since they use commas if((separator!='.')&&(express.indexOf("if")==-1)) { //$NON-NLS-1$ int j = express.indexOf(separator); while(j>-1) { express = express.substring(0, j)+'.'+express.substring(j+1); j = express.indexOf(separator); } } MultiVarFunction f = new ParsedMultiVarFunction(express, names); value = f.evaluate(values); } catch(ParserException ex) { value = Double.NaN; } return value; } /** * Returns an ObjectLoader to save and load data for this class. * * @return the object loader */ public static XML.ObjectLoader getLoader() { return new Loader(); } /** * A class to save and load data for this class. */ static class Loader implements XML.ObjectLoader { /** * Saves an object's data to an XMLControl. * * @param control the control to save to * @param obj the object to save */ public void saveObject(XMLControl control, Object obj) { Parameter p = (Parameter) obj; control.setValue("name", p.getName()); //$NON-NLS-1$ control.setValue("function", p.getExpression()); //$NON-NLS-1$ control.setValue("editable", p.isExpressionEditable()); //$NON-NLS-1$ control.setValue("name_editable", p.isNameEditable()); //$NON-NLS-1$ control.setValue("description", p.getDescription()); //$NON-NLS-1$ } /** * Creates a new object. * * @param control the control with the object data * @return the newly created object */ public Object createObject(XMLControl control) { String name = control.getString("name"); //$NON-NLS-1$ String f = control.getString("function"); //$NON-NLS-1$ return new Parameter(name, f); } /** * Loads an object with data from an XMLControl. * * @param control the control * @param obj the object * @return the loaded object */ public Object loadObject(XMLControl control, Object obj) { Parameter p = (Parameter) obj; if(control.getPropertyNames().contains("editable")) { //$NON-NLS-1$ p.setExpressionEditable(control.getBoolean("editable")); //$NON-NLS-1$ } if(control.getPropertyNames().contains("name_editable")) { //$NON-NLS-1$ p.setNameEditable(control.getBoolean("name_editable")); //$NON-NLS-1$ } p.setDescription(control.getString("description")); //$NON-NLS-1$ return obj; } } } /* * Open Source Physics software is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be * released under the GNU GPL license. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston MA 02111-1307 USA or view the license online at * http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */