/*
* 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
*/