CaRMtl/rene/zirkel/expression/Expression.java

2785 lines
64 KiB
Java

/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.zirkel.expression;
import java.util.Enumeration;
import rene.util.MyVector;
import rene.gui.Global;
import rene.zirkel.construction.Construction;
import rene.zirkel.construction.ConstructionException;
import rene.zirkel.construction.DepList;
import rene.zirkel.objects.AngleObject;
import rene.zirkel.objects.ConstructionObject;
import rene.zirkel.objects.EquationXYObject;
import rene.zirkel.objects.Evaluator;
import rene.zirkel.objects.FunctionObject;
import rene.zirkel.objects.InsideObject;
import rene.zirkel.objects.PointObject;
import rene.zirkel.objects.PrimitiveLineObject;
import rene.zirkel.objects.SimulationObject;
import rene.zirkel.objects.TrackObject;
import rene.zirkel.objects.UserFunctionObject;
import rene.zirkel.objects.VectorObject;
/*
This file contains classes for computing arithmetic expression. Those
classes might be useful elsewhere. However, variables evaluate to sizes of
construction objects or values of expressions here.
*/
/**
* This class holds information abut the current position in the scanned text.
*/
class ExpressionText {
char A[];
int N;
Construction C;
ConstructionObject O;
DepList DL;
String Var[];
boolean NoCircles;
public ExpressionText(final String S, final Construction c,
final ConstructionObject o, final DepList dl,
final boolean nocircles) {
A = S.toCharArray();
N = 0;
C = c;
O = o;
DL = dl;
NoCircles = nocircles;
}
public void setVar(final String t[]) {
Var = t;
}
public boolean isVar(final String var) {
if (Var == null) {
return false;
}
for (final String element : Var) {
if (element.equals(var)) {
return true;
}
}
return false;
}
public char next(final boolean quotes) {
if (!quotes) {
skipblanks();
}
if (N < A.length) {
return A[N];
} else {
return (char) 0;
}
}
public char next() {
return next(false);
}
public char nextnext() {
skipblanks();
if (N + 1 < A.length) {
return A[N + 1];
} else {
return (char) 0;
}
}
public void advance(final boolean quotes) {
if (!quotes) {
skipblanks();
}
N++;
}
public void advance() {
advance(false);
}
public Construction getConstruction() {
return C;
}
public ConstructionObject getObject() {
return O;
}
public DepList getDepList() {
return DL;
}
public void skipblanks() {
while (N < A.length && A[N] == ' ') {
N++;
}
}
public boolean nocircles() {
return NoCircles;
}
}
/**
* basic = (sum) basic = elementary
*/
class BasicExpression {
BasicExpression E;
static final int MINUS = -1, PLUS = 1;
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
if (t.next() == '-') {
t.advance();
return scan(t, MINUS);
}
if (t.next() == '+') {
t.advance();
return scan(t, PLUS);
}
if (t.next() == '(') {
return new BracketExpression(scanBracket(t));
}
return ElementaryExpression.scan(t);
}
public static BasicExpression scan(final ExpressionText t, final int sign)
throws ConstructionException {
if (sign == MINUS) {
if (t.next() == '(') {
return new MinusExpression(scanBracket(t));
}
return new MinusExpression(ElementaryExpression.scan(t));
}
if (t.next() == '(') {
return scanBracket(t);
}
return ElementaryExpression.scan(t);
}
public static BasicExpression scanBracket(final ExpressionText t)
throws ConstructionException {
t.advance();
final BasicExpression E = TopExpression.scan(t);
if (t.next() == ')') {
t.advance();
} else {
throw new ConstructionException(Global.name("exception.bracket"));
}
return E;
}
public double getValue() throws ConstructionException {
throw new ConstructionException("");
}
public void translate() {
}
public boolean isNumber() {
return false;
}
public void reset() {
}
public boolean isLogical() {
return false;
}
}
/**
* double = 34.45879 double = +34.45879 double = -34.45879
*/
class DoubleExpression extends BasicExpression {
double X;
public DoubleExpression(final double x) {
X = x;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
boolean Punkt = false, Digit = false, Expo = false;
String num = "";
char c = t.next();
if ((c == '+') || (c == '-')) {
num += c;
t.advance();
}
while (true) {
c = t.next();
if (c >= '0' && c <= '9') {
num += c;
t.advance();
Digit = true;
} else if (c == '.') {
if (Punkt) {
throw new ConstructionException(Global.name("exception.dot"));
}
Punkt = true;
num += c;
t.advance();
} else if ((Digit) && (c == 'E')) {
if (Expo) {
throw new ConstructionException(
"Exponential notation error");
}
Expo = true;
num += c;
t.advance();
c = t.next();
if ((c == '+') || (c == '-')) {
num += c;
t.advance();
}
} else {
break;
}
}
if (!Digit) {
throw new ConstructionException(Global.name("exception.nodigit"));
}
return new DoubleExpression(Double.valueOf(num).doubleValue());
}
@Override
public double getValue() throws ConstructionException {
return X;
}
@Override
public String toString() {
String s = "" + X;
if (s.endsWith(".0")) {
s = s.substring(0, s.length() - 2);
}
return s;
}
@Override
public void translate() {
}
@Override
public boolean isNumber() {
return true;
}
}
/**
* object = @name object = @"name"
*/
class FindObjectExpression extends ObjectExpression implements Translator {
String Name;
String Var = null;
Construction C;
ConstructionObject O = null; // found object
public FindObjectExpression(final String name, final Construction c) {
super(null);
Name = name;
C = c;
}
@Override
public ConstructionObject getObject() {
if (C == null) {
return null;
}
if (O != null && O.getConstruction() == C && O.isInConstruction()
&& O.getName().equals(Name)) {
return O;
}
return O = C.find(Name);
}
@Override
public double getValue() throws ConstructionException {
if (C == null) {
throw new InvalidException("");
}
if (O != null && O.getConstruction() == C && O.isInConstruction()
&& O.getName().equals(Name)) {
return O.getValue();
}
O = C.find(Name);
if (O == null) {
throw new InvalidException("");
}
return O.getValue();
}
public static BasicExpression scan(final ExpressionText t,
final boolean quotes) throws ConstructionException {
if (!quotes && t.next() == '\"') {
t.advance();
final BasicExpression E = scan(t, true);
if (t.next() != '\"') {
throw new ConstructionException(Global.name("exception.quotes"));
}
t.advance();
return E;
}
final StringBuffer b = new StringBuffer();
while (true) {
final char c = t.next(quotes);
if (!(Character.isLetterOrDigit(c) || c == '\\' || c == '\''
|| (quotes && c != '\"' && c != 0) || (quotes && c == ' '))) {
break;
}
b.append(c);
t.advance(quotes);
}
if (!quotes && t.next() == '(') {
return FunctionExpression.scan(t, b.toString());
}
final String s = b.toString();
return new FindObjectExpression(s, t.getConstruction());
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
return scan(t, false);
}
@Override
public void translate() {
C = C.getTranslation();
C.addTranslator(this);
}
@Override
public String toString() {
if (Var != null) {
return Var;
}
return "@" + ObjectExpression.quote(Name);
}
/**
* Used to translate expressions with @P in macros
*/
@Override
public void laterTranslate(final Construction from) {
if (C == null) {
return;
}
final ConstructionObject o = from.find(Name);
if (o == null || o.getTranslation() == null) {
from.addError(ConstructionObject.text1(Global.name("warning.macrodefinition"), Name));
return;
}
Name = o.getTranslation().getName();
O = null;
}
}
/**
* object = name object = "name"
*/
class ObjectExpression extends BasicExpression {
ConstructionObject O;
String Var = null;
public ObjectExpression(final ConstructionObject o) {
O = o;
}
@Override
public double getValue() throws ConstructionException {
if (!O.valid()) {
throw new InvalidException("");
}
if (Var != null && (O instanceof FunctionObject)) {
return ((FunctionObject) O).getValue(Var);
}
if (Var != null && (O instanceof UserFunctionObject)) {
return ((UserFunctionObject) O).getValue(Var);
}
if (Var != null && (O instanceof EquationXYObject)) {
return ((EquationXYObject) O).getValue(Var);
}
return O.getValue();
}
public ConstructionObject getObject() {
return O;
}
public static BasicExpression scan(final ExpressionText t,
final boolean quotes) throws ConstructionException {
if (!quotes && t.next() == '\"') {
t.advance();
final BasicExpression E = scan(t, true);
if (t.next() != '\"') {
throw new ConstructionException(Global.name("exception.quotes"));
}
t.advance();
return E;
}
final StringBuffer b = new StringBuffer();
while (true) {
final char c = t.next(quotes);
if (!(Character.isLetterOrDigit(c) || c == '\\' || c == '\''
|| (quotes && c != '\"' && c != 0) || (quotes && c == ' '))) {
break;
}
b.append(c);
t.advance(quotes);
}
if (!quotes && t.next() == '(') {
return FunctionExpression.scan(t, b.toString());
}
final String s = b.toString();
if (s.equals("pi")) {
return new ConstantExpression("pi", Math.PI);
}
if (s.equals("valid")) {
return new ValidExpression(true);
}
if (s.equals("invalid")) {
return new ValidExpression(false);
}
if (s.equals("this")) {
t.getDepList().add(t.getObject());
return new ObjectExpression(t.getObject());
}
if (s.equals("windoww")) {
return new ConstructionExpression(t.getConstruction(),
ConstructionExpression.WIDTH);
}
if (s.equals("windowh")) {
return new ConstructionExpression(t.getConstruction(),
ConstructionExpression.HEIGHT);
}
if (s.equals("windowcx")) {
return new ConstructionExpression(t.getConstruction(),
ConstructionExpression.CENTERX);
}
if (s.equals("windowcy")) {
return new ConstructionExpression(t.getConstruction(),
ConstructionExpression.CENTERY);
}
if (s.equals("pixel")) {
return new ConstructionExpression(t.getConstruction(),
ConstructionExpression.PIXEL);
}
if (t.isVar(s)) {
final ObjectExpression oe = new ObjectExpression(t.getObject());
oe.Var = s;
return oe;
}
ConstructionObject o = t.getConstruction().findInclusive(s,
t.getObject());
if (o == null) {
o = t.getConstruction().find(s);
if (o == null) {
if (t.getConstruction().loading()) {
return new FindObjectExpression(s, t.getConstruction());
} else {
throw new ConstructionException(Global.name("exception.notfound")
+ " (" + s + ")");
}
}
// System.out.println("---");
// System.out.println(o.getName()+" "+t.getObject().getName());
// System.out.println(t.getConstruction().dependsOn(o,t.getObject()));
if (t.getConstruction().dependsOn(o, t.getObject())) {
if (t.nocircles()) {
throw new ConstructionException(ConstructionObject.text1(
Global.name("exception.depends"), s));
}
return new FindObjectExpression(s, t.getConstruction());
}
t.getConstruction().needsOrdering();
}
t.getDepList().add(o);
return new ObjectExpression(o);
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
if (t.next() == '@') {
t.advance();
return FindObjectExpression.scan(t);
}
return scan(t, false);
}
@Override
public void translate() {
O = O.getTranslation();
}
@Override
public String toString() {
if (Var != null) {
return Var;
}
return quote(O.getName());
}
static public String quote(final String name) {
boolean quotes = false;
for (int i = 0; i < name.length(); i++) {
if (!Character.isLetterOrDigit(name.charAt(i))) {
quotes = true;
break;
}
}
if (quotes) {
return "\"" + name + "\"";
} else {
return name;
}
}
}
/**
* @author Rene
*
* Evaluates a user funktion (a FunctionObject). The Y-expression of
* this function is used.
*
*/
class UserFunctionExpression extends BasicExpression {
ConstructionObject F;
BasicExpression E[];
double X[];
public UserFunctionExpression(final ConstructionObject f,
final BasicExpression e[]) {
F = f;
E = e;
X = new double[E.length];
}
@Override
public double getValue() throws ConstructionException {
for (int i = 0; i < E.length; i++) {
X[i] = E[i].getValue();
}
if (F instanceof FunctionObject) {
return ((FunctionObject) F).evaluateF(X);
}
return ((UserFunctionObject) F).evaluateF(X);
}
@Override
public void translate() {
for (final BasicExpression element : E) {
element.translate();
}
if (F instanceof FunctionObject) {
F = (FunctionObject) F.getTranslation();
} else {
F = (UserFunctionObject) F.getTranslation();
}
}
@Override
public void reset() {
for (final BasicExpression element : E) {
element.reset();
}
}
@Override
public String toString() {
String ex = E[0].toString();
for (int i = 1; i < E.length; i++) {
ex = ex + "," + E[i].toString();
}
return F.getName() + "(" + ex + ")";
}
}
class SimulationExpression extends BasicExpression {
ConstructionObject SO;
ConstructionObject Container, F;
BasicExpression E;
Construction C;
public SimulationExpression(final ConstructionObject so,
final ConstructionObject c, final BasicExpression e,
final ConstructionObject f) {
SO = so;
Container = c;
E = e;
F = f;
C = c.getConstruction();
}
@Override
public double getValue() throws ConstructionException {
if (C.BlockSimulation) {
throw new ConstructionException(Global.name("exception.simmulation.block"));
}
try {
final double aa = E.getValue();
C.BlockSimulation = true;
((SimulationObject) SO).setSimulationValue(aa);
F.getConstruction().validate(F, SO);
final double res = F.getValue();
((SimulationObject) SO).resetSimulationValue();
F.getConstruction().validate(F, SO);
C.BlockSimulation = false;
return res;
} catch (final Exception e) {
C.BlockSimulation = false;
throw new ConstructionException("");
}
}
@Override
public void translate() {
E.translate();
SO = SO.getTranslation();
Container = Container.getTranslation();
F = F.getTranslation();
}
@Override
public void reset() {
E.reset();
}
@Override
public String toString() {
return "simulate(" + SO.getName() + "," + E.toString() + ","
+ F.getName() + ")";
}
}
/**
* function = sin(parameter) etc. function = x(point) function = y(point)
*/
class FunctionExpression extends BasicExpression {
int F;
BasicExpression E[];
int NParams;
public FunctionExpression(final int f, final BasicExpression e) {
F = f;
E = new BasicExpression[1];
E[0] = e;
NParams = 1;
}
public FunctionExpression(final int f, final BasicExpression e,
final BasicExpression ee) {
F = f;
E = new BasicExpression[2];
E[0] = e;
E[1] = ee;
NParams = 2;
}
public FunctionExpression(final int f, final BasicExpression e,
final BasicExpression ee, final BasicExpression eee) {
F = f;
E = new BasicExpression[3];
E[0] = e;
E[1] = ee;
E[2] = eee;
NParams = 3;
}
/**
* @author Vincent Robert, 2nde SI 3, LPO Roland-Garros
* pgcd de deux nombres
* @param x entier premier nombre
* @param y entier second nombre
* @return le pgcd
*/
public int pgcd(int x, int y){
int a=Math.abs(x);
int b=Math.abs(y);
int c;
while(b>0){
c=a%b;
a=b;
b=c;
}
return a;
}
final static String Functions[] = { "sin", "cos", "tan", "arcsin",
"arccos", "arctan", "sqrt", "exp", "log", "round", "x", "y",
"floor", "ceil", "d", "a", "angle180", "angle360", "abs", "scale",
"sign", "d", "sum", "if", "deg", "rad", "integrate", "zero",
"diff", "min", "max", "length", "rsin", "rcos", "rtan", "rarcsin",
"rarccos", "rarctan", "sinhyp", "coshyp", "z", "simulate",
"inside", "random", "old", "ratan2", "atan2", "tanhyp", "Argsinh",
"Argcosh", "Argtanh", "div","mod", "gcd", "lcm", "x3D", "y3D", "z3D", "d3D"};
final static int NX = 10, NY = 11, ND = 14, NA = 15, NS = 19, NSUM = 22,
NIF = 23, NINT = 26, NZERO = 27, NDIFF = 28, NMIN = 29, NMAX = 30,
NLENGTH = 31, NZ = 40, NSIM = 41, NINSIDE = 42, NRANDOM = 43,
NOLD = 44, NRATAN2=45, NATAN2=46, NDIV=51, NMOD=52, NGCD=53, NLCM=54, NX3D=55, NY3D=56, NZ3D= 57, ND3D=58 ;
public static BasicExpression scan(final ExpressionText t, final String name)
throws ConstructionException {
int f = -1;
for (int i = 0; i < Functions.length; i++) {
if (name.equals(Functions[i])) {
f = i;
break;
}
}
if (f < 0) {
boolean forward = false;
ConstructionObject o = t.getConstruction()
.find(name, t.getObject());
if (o == null) {
o = t.getConstruction().find(name);
forward = true;
}
if (o != null
&& (o instanceof FunctionObject || o instanceof UserFunctionObject)
&& !(o == t.getObject())
&& !t.getConstruction().dependsOn(o, t.getObject())) {
if (t.next() != '(') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final MyVector ex = new MyVector();
while (true) {
final BasicExpression e = TopExpression.scan(t);
ex.addElement(e);
if (t.next() == ')') {
break;
}
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
}
t.advance();
t.getDepList().add(o);
if (forward) {
t.getConstruction().needsOrdering();
}
final BasicExpression exp[] = new BasicExpression[ex.size()];
ex.copyInto(exp);
return new UserFunctionExpression(o, exp);
}
throw new ConstructionException(Global.name("exception.function")
+ " (" + name + ")");
}
if (t.next() != '(') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
BasicExpression e = TopExpression.scan(t);
if (f == NX || f == NY || f == NZ) {
if (e instanceof FindObjectExpression) {
e = new FunctionExpression(f, e);
} else if (e instanceof ObjectExpression
&& ((ObjectExpression) e).getObject() instanceof PointObject) {
e = new FunctionExpression(f, e);
} else if (e instanceof ObjectExpression
&& ((ObjectExpression) e).getObject() instanceof PrimitiveLineObject) {
e = new FunctionExpression(f, e);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
}
else if (f == NX3D || f == NY3D || f == NZ3D) {
if (e instanceof FindObjectExpression) {
e = new FunctionExpression(f, e);
} else if (e instanceof ObjectExpression
&& ((ObjectExpression) e).getObject() instanceof PointObject) {
e = new FunctionExpression(f, e);
} else if (e instanceof ObjectExpression
&& ((ObjectExpression) e).getObject() instanceof PrimitiveLineObject) {
e = new FunctionExpression(f, e);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
}
else if (f == ND) {
if (t.next() != ',') {
e = new DExpression(e);
} else {
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (((e instanceof ObjectExpression && ((ObjectExpression) e)
.getObject() instanceof PointObject) || e instanceof FindObjectExpression)
&& ((ee instanceof ObjectExpression && ((ObjectExpression) ee)
.getObject() instanceof PointObject) || ee instanceof FindObjectExpression)) {
e = new FunctionExpression(f, e, ee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
}
}
else if (f == ND3D) {
if (t.next() != ',') {
e = new D3DExpression(e);
} else {
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (((e instanceof ObjectExpression && ((ObjectExpression) e)
.getObject() instanceof PointObject) || e instanceof FindObjectExpression)
&& ((ee instanceof ObjectExpression && ((ObjectExpression) ee)
.getObject() instanceof PointObject) || ee instanceof FindObjectExpression)) {
e = new FunctionExpression(f, e, ee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
}
}
else if (f == NOLD) {
if (t.next() != ',') {
e = new OldExpression(e);
} else {
t.advance();
final BasicExpression ee = TopExpression.scan(t);
e = new OldExpression(e, ee);
}
} else if (f == NA) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression eee = TopExpression.scan(t);
if (((e instanceof ObjectExpression && ((ObjectExpression) e)
.getObject() instanceof PointObject) || e instanceof FindObjectExpression)
&& ((ee instanceof ObjectExpression && ((ObjectExpression) ee)
.getObject() instanceof PointObject) || ee instanceof FindObjectExpression)
&& ((eee instanceof ObjectExpression && ((ObjectExpression) eee)
.getObject() instanceof PointObject) || eee instanceof FindObjectExpression)) {
e = new FunctionExpression(f, e, ee, eee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
} else if (f == NS) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression eee = TopExpression.scan(t);
e = new FunctionExpression(f, e, ee, eee);
} else if (f == NSUM) {
if (t.next() != ',') {
e = new CumSumExpression(e);
} else {
t.advance();
final BasicExpression ee = TopExpression.scan(t);
e = new CumSumExpression(e, ee);
}
} else if (f == NRANDOM) {
if (t.next() != ',') {
e = new RandomExpression(e);
} else {
t.advance();
final BasicExpression ee = TopExpression.scan(t);
e = new RandomExpression(e, ee);
}
} else if (f == NIF) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression eee = TopExpression.scan(t);
e = new IfExpression(e, ee, eee);
} else if (f == NINT || f == NZERO || f == NMIN || f == NMAX
|| f == NLENGTH || f==NRATAN2 || f==NATAN2
|| f == NDIV || f== NMOD || f == NGCD || f == NLCM) {
if (!(e instanceof ObjectExpression)||t.isVar(e.toString())) {
if (f == NMAX || f == NMIN || f==NRATAN2 || f==NATAN2
|| f == NDIV || f == NMOD || f == NGCD || f == NLCM) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
e = new FunctionExpression(f, e, ee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
} else {
final boolean function = ((ObjectExpression) e).getObject() instanceof Evaluator
|| ((ObjectExpression) e).getObject() instanceof TrackObject;
if ((f == NINT || f == NLENGTH) && t.next() == ')') {
if (!function) {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
e = new FunctionExpression(f, e);
} else if (f == NLENGTH) {
throw new ConstructionException(Global.name("exception.parameter"));
} else {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (function) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression eee = TopExpression.scan(t);
e = new FunctionExpression(f, e, ee, eee);
} else if (f == NMIN || f == NMAX || f == NATAN2
|| f == NRATAN2 || f == NDIV || f == NMOD
|| f == NGCD || f == NLCM) {
e = new FunctionExpression(f, e, ee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
}
}
} else if (f == NDIFF) {
if (!(e instanceof ObjectExpression)
|| !(((ObjectExpression) e).getObject() instanceof Evaluator)) {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
e = new FunctionExpression(f, e, ee);
} else if (f == NSIM) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression eee = TopExpression.scan(t);
if ((e instanceof ObjectExpression && ((ObjectExpression) e)
.getObject() instanceof SimulationObject)
|| !(eee instanceof ObjectExpression)) {
final ConstructionObject SO = ((ObjectExpression) e)
.getObject();
if (t.getConstruction().dependsOn(SO, t.getObject())) {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
e = new SimulationExpression(
((ObjectExpression) e).getObject(), t.getObject(), ee,
((ObjectExpression) eee).getObject());
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
} else if (f == NINSIDE) {
if (t.next() != ',') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
final BasicExpression ee = TopExpression.scan(t);
if (((e instanceof ObjectExpression && ((ObjectExpression) e)
.getObject() instanceof PointObject) || e instanceof FindObjectExpression)
&& ((ee instanceof ObjectExpression && ((ObjectExpression) ee)
.getObject() instanceof InsideObject) || ee instanceof FindObjectExpression)) {
e = new FunctionExpression(f, e, ee);
} else {
throw new ConstructionException(Global.name("exception.parameter")
+ " (" + Functions[f] + ")");
}
} else {
e = new FunctionExpression(f, e);
}
if (t.next() != ')') {
throw new ConstructionException(Global.name("exception.parameter"));
}
t.advance();
return e;
}
@Override
public double getValue() throws ConstructionException {
PointObject P, PP, PPP;
double cc;
switch (F) {
case NX:
cc = getPointLineX(0);
return cc;
case NY:
cc = getPointLineY(0);
return cc;
case NX3D:
cc = getPointLineX3D(0);
return cc;
case NY3D:
cc = getPointLineY3D(0);
return cc;
case NZ3D:
cc = getPointLineZ3D(0);
return cc;
case NZ:
P = getPoint(0);
if (!P.valid()) {
throw new InvalidException(Global.name("exception.invalid"));
}
return P.getZ();
case ND:
P = getPoint(0);
PP = getPoint(1);
if (!P.valid() || !PP.valid()) {
throw new InvalidException(Global.name("exception.invalid"));
}
double dx = P.getX() - PP.getX();
double dy = P.getY() - PP.getY();
return Math.sqrt(dx * dx + dy * dy);
case ND3D:
P = getPoint(0);
PP = getPoint(1);
if (!P.valid() || !PP.valid()) {
throw new InvalidException(Global.name("exception.invalid"));
}
double dx3D = P.getX3D() - PP.getX3D();
double dy3D = P.getY3D() - PP.getY3D();
double dz3D = P.getZ3D() - PP.getZ3D();
return Math.sqrt(dx3D * dx3D + dy3D * dy3D + dz3D * dz3D);
case NA:
P = getPoint(0);
PP = getPoint(1);
PPP = getPoint(2);
if (!P.valid() || !PP.valid() || !PPP.valid()) {
throw new InvalidException(Global.name("exception.invalid"));
}
dx = P.getX() - PP.getX();
dy = P.getY() - PP.getY();
final double dx1 = PPP.getX() - PP.getX();
final double dy1 = PPP.getY() - PP.getY();
double a = Math.atan2(dx, dy) - Math.atan2(dx1, dy1);
a = a / Math.PI * 180;
if (a < 0) {
a += 360;
}
if (a > 360) {
a -= 360;
}
return a;
case NS:
final double x = E[0].getValue(),
xa = E[1].getValue(),
xb = E[2].getValue();
if (x < xa || x >= xb || xb <= xa) {
throw new InvalidException(Global.name("exception.invalid"));
}
return (x - xa) / (xb - xa);
case NINT:
if (((ObjectExpression) E[0]).getObject() instanceof Evaluator) {
final Evaluator F = (Evaluator) (((ObjectExpression) E[0])
.getObject());
if (E.length > 1) {
final double aa = E[1].getValue(), bb = E[2].getValue();
return Romberg.compute(F, aa, bb, 10, 1e-10, 10);
} else if (F instanceof FunctionObject) {
return ((FunctionObject) F).getIntegral();
}
} else {
final TrackObject TO = (TrackObject) (((ObjectExpression) E[0])
.getObject());
if (E.length > 1) {
final double aa = E[1].getValue(), bb = E[2].getValue();
return TO.getSum(aa, bb);
} else {
return TO.getSum();
}
}
case NLENGTH:
if (((ObjectExpression) E[0]).getObject() instanceof FunctionObject) {
final FunctionObject F = (FunctionObject) (((ObjectExpression) E[0])
.getObject());
return F.getLength();
} else {
final TrackObject TO = (TrackObject) (((ObjectExpression) E[0])
.getObject());
return TO.getLength();
}
case NZERO:
Evaluator F = (Evaluator) (((ObjectExpression) E[0]).getObject());
double aa = E[1].getValue(),
bb = E[2].getValue();
return Secant.compute(F, aa, bb, 1e-10);
case NDIFF:
F = (Evaluator) (((ObjectExpression) E[0]).getObject());
aa = E[1].getValue();
return (F.evaluateF(aa + 1e-7) - F.evaluateF(aa - 1e-7)) / 2e-7;
case NMIN:
if (NParams == 2) {
return Math.min(E[0].getValue(), E[1].getValue());
} else {
F = (Evaluator) (((ObjectExpression) E[0]).getObject());
aa = E[1].getValue();
bb = E[2].getValue();
return ConvexMin.computeMin(F, aa, bb, 1e-10);
}
case NMAX:
if (NParams == 2) {
return Math.max(E[0].getValue(), E[1].getValue());
} else {
F = (Evaluator) (((ObjectExpression) E[0]).getObject());
aa = E[1].getValue();
bb = E[2].getValue();
return ConvexMin.computeMax(F, aa, bb, 1e-10);
}
case NINSIDE:
P = getPoint(0);
final InsideObject IO = (InsideObject) (((ObjectExpression) E[1])
.getObject());
return IO.containsInside(P);
}
double x = E[0].getValue();
switch (F) {
case 0:
return Math.sin(x / 180 * Math.PI);
case 1:
return Math.cos(x / 180 * Math.PI);
case 2:
return Math.tan(x / 180 * Math.PI);
case 3:
return Math.asin(x) / Math.PI * 180;
case 4:
return Math.acos(x) / Math.PI * 180;
case 5:
return Math.atan(x) / Math.PI * 180;
case 6:
return Math.sqrt(x);
case 7:
return Math.exp(x);
case 8:
return Math.log(x);
case 9:
return Math.round(x);
case 12:
return Math.floor(x);
case 13:
return Math.ceil(x);
case 16:
x = x / 360;
x -= Math.floor(x);
x = x * 360;
if (x < 180) {
return x;
} else {
return (x - 360);
}
case 17:
x /= 360;
x -= Math.floor(x);
return x * 360;
case 18:
return Math.abs(x);
case 20:
if (x > 0) {
return 1;
} else if (x == 0) {
return 0;
} else {
return -1;
}
case 24:
return (x / Math.PI * 180);
case 25:
return (x / 180 * Math.PI);
case 32:
return Math.sin(x);
case 33:
return Math.cos(x);
case 34:
return Math.tan(x);
case 35:
return Math.asin(x);
case 36:
return Math.acos(x);
case 37:
return Math.atan(x);
case 38:
return (Math.exp(x) - Math.exp(-x)) / 2;
case 39:
return (Math.exp(x) + Math.exp(-x)) / 2;
case 47:
return (Math.exp(x) - Math.exp(-x))/(Math.exp(x) + Math.exp(-x));
case 48:
return Math.log(x+Math.sqrt(x*x+1));
case 49:
return Math.log(x+Math.sqrt(x*x-1));
case 50:
return Math.log((1+x)/(1-x))/2.0;
case 45://these two functions by S. Reyrolle
if(NParams==2){
return Math.atan2(x,E[1].getValue());
} else{
throw new ConstructionException(Global.name("exception.parameter"));
}
case 46:
if(NParams==2){
return Math.atan2(x,E[1].getValue())/ Math.PI * 180;
}else{
throw new ConstructionException(Global.name("exception.parameter"));
}
case NDIV:
if(NParams==2){
return Math.floor(x/E[1].getValue());
}else{
throw new ConstructionException(Global.name("exception.parameter"));
}
case NMOD:
if(NParams==2){
return x%(E[1].getValue());
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
case NGCD:
if(NParams==2){
return pgcd((int) x,(int) E[1].getValue());
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
case NLCM:
if(NParams==2){
return x*E[1].getValue()/pgcd((int) x,(int) E[1].getValue());
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
}
throw new ConstructionException("");
}
public double getPointLineX(final int n) throws ConstructionException {
PointObject p;
PrimitiveLineObject l;
VectorObject s;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p.getX();
} catch (final Exception e) {
try{
s=(VectorObject) ((ObjectExpression) E[n]).getObject();
if (!s.valid()){
throw new ConstructionException("exception.invalid");
}
return s.getDeltaX();
} catch (final Exception eee) {
}
try {
l = (PrimitiveLineObject) ((ObjectExpression) E[n]).getObject();
if (!l.valid()) {
throw new ConstructionException("exception.invalid");
}
return l.getDX();
} catch (final Exception ee) {
throw new ConstructionException("exception.notfound");
}
}
}
public double getPointLineY(final int n) throws ConstructionException {
PointObject p;
PrimitiveLineObject l;
VectorObject s;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p.getY();
} catch (final Exception e) {
try{
s=(VectorObject) ((ObjectExpression) E[n]).getObject();
if (!s.valid()){
throw new ConstructionException("exception.invalid");
}
return s.getDeltaY();
} catch (final Exception eee) {
}
try {
l = (PrimitiveLineObject) ((ObjectExpression) E[n]).getObject();
if (!l.valid()) {
throw new ConstructionException("exception.invalid");
}
return l.getDY();
} catch (final Exception ee) {
throw new ConstructionException("exception.notfound");
}
}
}
public double getPointLineX3D(final int n) throws ConstructionException {
PointObject p;
PrimitiveLineObject l;
VectorObject s;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p.getX3D();
} catch (final Exception e) {
try{
s=(VectorObject) ((ObjectExpression) E[n]).getObject();
if (!s.valid()){
throw new ConstructionException("exception.invalid");
}
return s.getDeltaX3D();
} catch (final Exception eee) {
}
try {
l = (PrimitiveLineObject) ((ObjectExpression) E[n]).getObject();
if (!l.valid()) {
throw new ConstructionException("exception.invalid");
}
return l.getDX3D();
} catch (final Exception ee) {
throw new ConstructionException("exception.notfound");
}
}
}
public double getPointLineY3D(final int n) throws ConstructionException {
PointObject p;
PrimitiveLineObject l;
VectorObject s;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p.getY3D();
} catch (final Exception e) {
try{
s=(VectorObject) ((ObjectExpression) E[n]).getObject();
if (!s.valid()){
throw new ConstructionException("exception.invalid");
}
return s.getDeltaY3D();
} catch (final Exception eee) {
}
try {
l = (PrimitiveLineObject) ((ObjectExpression) E[n]).getObject();
if (!l.valid()) {
throw new ConstructionException("exception.invalid");
}
return l.getDY3D();
} catch (final Exception ee) {
throw new ConstructionException("exception.notfound");
}
}
}
public double getPointLineZ3D(final int n) throws ConstructionException {
PointObject p;
PrimitiveLineObject l;
VectorObject s;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p.getZ3D();
} catch (final Exception e) {
try{
s=(VectorObject) ((ObjectExpression) E[n]).getObject();
if (!s.valid()){
throw new ConstructionException("exception.invalid");
}
return s.getDeltaZ3D();
} catch (final Exception eee) {
}
try {
l = (PrimitiveLineObject) ((ObjectExpression) E[n]).getObject();
if (!l.valid()) {
throw new ConstructionException("exception.invalid");
}
return l.getDZ3D();
} catch (final Exception ee) {
throw new ConstructionException("exception.notfound");
}
}
}
public PointObject getPoint(final int n) throws ConstructionException {
PointObject p;
try {
p = (PointObject) ((ObjectExpression) E[n]).getObject();
} catch (final Exception e) {
throw new ConstructionException("exception.notfound");
}
if (!p.valid()) {
throw new ConstructionException("exception.invalid");
}
return p;
}
@Override
public void translate() {
for (int i = 0; i < NParams; i++) {
E[i].translate();
}
}
@Override
public void reset() {
for (int i = 0; i < NParams; i++) {
E[i].reset();
}
}
@Override
public String toString() {
String s = Functions[F] + "(";
for (int i = 0; i < NParams; i++) {
if (i > 0) {
s = s + ",";
}
s = s + E[i];
}
return s + ")";
}
}
class OldExpression extends FunctionExpression {
double oldvalue1 = Double.NaN, oldvalue2 = Double.NaN;
public OldExpression(final BasicExpression e) {
super(NOLD, e);
}
public OldExpression(final BasicExpression e, final BasicExpression ee) {
super(NOLD, e, ee);
}
@Override
public double getValue() throws ConstructionException {
final double x = E[0].getValue();
final double p = (NParams > 1) ? E[1].getValue() : 0;
if (Double.isNaN(oldvalue1)) {
oldvalue1 = x;
}
if (Double.isNaN(oldvalue2)) {
oldvalue2 = x;
}
if (p == 1) {
oldvalue1 = oldvalue2;
oldvalue2 = x;
} else {
if (x != oldvalue2) {
oldvalue1 = oldvalue2;
oldvalue2 = x;
}
}
return oldvalue1;
}
@Override
public void reset() {
super.reset();
}
}
class DExpression extends FunctionExpression {
double Old = 0;
double Old1 = 0;
boolean start = false;
public DExpression(final BasicExpression e) {
super(21, e);
}
@Override
public double getValue() throws ConstructionException {
if (E[0] instanceof ObjectExpression) {
final ConstructionObject o = ((ObjectExpression) E[0]).getObject();
if (o instanceof PointObject) {
final PointObject p = (PointObject) o;
if (p.dontUpdate()) {
return 0;
}
final double x = p.getX(), y = p.getY();
if (start) {
final double res = (x - Old) * (x - Old) + (y - Old1)
* (y - Old1);
Old = x;
Old1 = y;
return Math.sqrt(res);
}
Old = x;
Old1 = y;
start = true;
return 0;
} else if (o instanceof AngleObject) {
final AngleObject a = (AngleObject) o;
final double x = a.getValue();
if (start) {
double res = x - Old;
if (res < -180) {
res += 180;
}
if (res > 180) {
res -= 180;
}
Old = x;
return res;
}
Old = x;
start = true;
return 0;
}
}
final double x = E[0].getValue();
double res;
if (start) {
res = x - Old;
} else {
res = 0;
start = true;
}
Old = x;
return res;
}
@Override
public void reset() {
start = false;
super.reset();
}
}
class D3DExpression extends FunctionExpression {
double Old = 0;
double Old1 = 0;
double Old2 = 0;
boolean start = false;
public D3DExpression(final BasicExpression e) {
super(58, e);
}
@Override
public double getValue() throws ConstructionException {
if (E[0] instanceof ObjectExpression) {
final ConstructionObject o = ((ObjectExpression) E[0]).getObject();
if (o instanceof PointObject) {
final PointObject p = (PointObject) o;
if (p.dontUpdate()) {
return 0;
}
final double x3D = p.getX3D(), y3D = p.getY3D(), z3D = p.getZ3D();
if (start) {
final double res = (x3D - Old) * (x3D - Old) + (y3D - Old1) * (y3D - Old1) + (z3D - Old2) * (z3D - Old2);
Old = x3D;
Old1 = y3D;
Old2 = y3D;
return Math.sqrt(res);
}
Old = x3D;
Old1 = y3D;
Old2 = z3D;
start = true;
return 0;
} else if (o instanceof AngleObject) {
final AngleObject a = (AngleObject) o;
final double x = a.getValue();
if (start) {
double res = x - Old;
if (res < -180) {
res += 180;
}
if (res > 180) {
res -= 180;
}
Old = x;
return res;
}
Old = x;
start = true;
return 0;
}
}
final double x = E[0].getValue();
double res;
if (start) {
res = x - Old;
} else {
res = 0;
start = true;
}
Old = x;
return res;
}
@Override
public void reset() {
start = false;
super.reset();
}
}
class CumSumExpression extends FunctionExpression {
double sum = 0;
public CumSumExpression(final BasicExpression e, final BasicExpression ee) {
super(22, e, ee);
}
public CumSumExpression(final BasicExpression e) {
super(22, e);
}
@Override
public double getValue() throws ConstructionException {
if (NParams > 1) {
try {
final double x = E[1].getValue();
if (x < 0) {
reset();
return sum;
}
} catch (final Exception e) {
sum = 0;
return sum;
}
}
sum += E[0].getValue();
return sum;
}
@Override
public void reset() {
sum = 0;
super.reset();
}
}
class RandomExpression extends FunctionExpression {
double rand = Double.NaN;
public RandomExpression(final BasicExpression e, final BasicExpression ee) {
super(NRANDOM, e, ee);
}
public RandomExpression(final BasicExpression e) {
super(NRANDOM, e);
}
@Override
public double getValue() throws ConstructionException {
if (NParams > 1) {
try {
final double r = E[0].getValue();
final double p = E[1].getValue();
if ((p == 1) || (Double.isNaN(rand))) {
rand = r * Math.random();
}
} catch (final Exception e) {
rand = 0;
return rand;
}
} else {
final double r = E[0].getValue();
rand = r * Math.random();
}
return rand;
}
@Override
public void reset() {
rand = 0;
super.reset();
}
}
class IfExpression extends FunctionExpression {
public IfExpression(final BasicExpression e, final BasicExpression ee,
final BasicExpression eee) {
super(23, e, ee, eee);
}
@Override
public double getValue() throws ConstructionException {
double v = 0;
try {
v = E[0].getValue();
} catch (final NoValueException e) {
if (e.isValid()) {
return E[1].getValue();
} else {
return E[2].getValue();
}
} catch (final ConstructionException e) {
return E[2].getValue();
}
if (E[0].isLogical()) {
if (v == 0) {
return E[2].getValue();
} else {
return E[1].getValue();
}
}
return E[1].getValue();
}
}
/**
* constant = pi
*/
class ConstantExpression extends BasicExpression {
double X;
String S;
public ConstantExpression(final String s, final double x) {
X = x;
S = s;
}
@Override
public double getValue() throws ConstructionException {
return X;
}
@Override
public void translate() {
}
@Override
public String toString() {
return S;
}
}
/**
* constant depending on construction
*/
class ConstructionExpression extends BasicExpression {
int Type;
Construction C;
final static int CENTERX = 0, CENTERY = 1, WIDTH = 2, HEIGHT = 3,
PIXEL = 4;
public ConstructionExpression(final Construction c, final int type) {
Type = type;
C = c;
}
@Override
public double getValue() throws ConstructionException {
if (C == null) {
return 0;
}
switch (Type) {
case WIDTH:
return C.getW();
case CENTERX:
return C.getX();
case CENTERY:
return C.getY();
case HEIGHT:
return C.getH();
case PIXEL:
return C.getPixel();
}
return 0;
}
@Override
public void translate() {
C = C.getTranslation();
}
@Override
public String toString() {
switch (Type) {
case WIDTH:
return "windoww";
case CENTERX:
return "windowcx";
case CENTERY:
return "windowcy";
case HEIGHT:
return "windowh";
case PIXEL:
return "pixel";
}
return "";
}
}
/**
* constant = valid,invalid
*/
class ValidExpression extends BasicExpression {
boolean V;
public ValidExpression(final boolean valid) {
V = valid;
}
@Override
public double getValue() throws ConstructionException {
if (V) {
return 0;
} else {
throw new ConstructionException("");
}
}
@Override
public void translate() {
}
@Override
public String toString() {
if (V) {
return "valid";
} else {
return "invalid";
}
}
}
/**
* Bracket = (Basic)
*/
class BracketExpression extends ElementaryExpression {
BasicExpression E;
public BracketExpression(final BasicExpression e) {
E = e;
}
@Override
public double getValue() throws ConstructionException {
return E.getValue();
}
@Override
public void translate() {
E.translate();
}
@Override
public String toString() {
return "(" + E.toString() + ")";
}
@Override
public boolean isNumber() {
return E.isNumber();
}
@Override
public void reset() {
E.reset();
}
}
/**
* element = double element = object (with value)
*/
abstract class ElementaryExpression extends BasicExpression {
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
try {
final BasicExpression E = DoubleExpression.scan(t);
return E;
} catch (final Exception e) {
}
try {
final BasicExpression E = ObjectExpression.scan(t);
return E;
} catch (final ConstructionException e) {
throw e;
} catch (final Exception e) {
}
throw new ConstructionException(Global.name("exception.elementary"));
}
@Override
abstract public boolean isNumber();
@Override
abstract public double getValue() throws ConstructionException;
}
/**
* E^E
*/
class PotenzExpression extends BasicExpression {
BasicExpression E1, E2;
public PotenzExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = BasicExpression.scan(t);
if (t.next() == '^' || (t.next() == '*' && t.nextnext() == '*')) {
if (t.next() == '*') {
t.advance();
}
t.advance();
return scan(t, E1);
}
return E1;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = BasicExpression.scan(t);
if (t.next() == '^' || (t.next() == '*' && t.nextnext() == '*')) {
if (t.next() == '*') {
t.advance();
}
t.advance();
return scan(t, new PotenzExpression(E, E1));
}
return new PotenzExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
return Math.pow(E1.getValue(), E2.getValue());
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "^" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
}
/**
* -E
*/
class MinusExpression extends ElementaryExpression {
BasicExpression E;
public MinusExpression(final BasicExpression e) {
E = e;
}
@Override
public double getValue() throws ConstructionException {
return -E.getValue();
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
if (t.next() != '-') {
return PotenzExpression.scan(t);
}
t.advance();
final BasicExpression E1 = PotenzExpression.scan(t);
return new MinusExpression(E1);
}
@Override
public void translate() {
E.translate();
}
@Override
public String toString() {
return "-" + E.toString();
}
@Override
public boolean isNumber() {
return E.isNumber();
}
@Override
public void reset() {
E.reset();
}
}
/**
* E/E
*/
class QuotientExpression extends BasicExpression {
BasicExpression E1, E2;
public QuotientExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = MinusExpression.scan(t);
if (t.next() == '/') {
t.advance();
return scan(t, new QuotientExpression(E, E1));
} else if (t.next() == '*' && t.nextnext() != '*') {
t.advance();
return ProductExpression.scan(t, new QuotientExpression(E, E1));
}
return new QuotientExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
return E1.getValue() / E2.getValue();
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "/" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
}
/**
* E*E
*/
class ProductExpression extends BasicExpression {
BasicExpression E1, E2;
public ProductExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = MinusExpression.scan(t);
if (t.next() == '*') {
t.advance();
return scan(t, E1);
} else if (t.next() == '/') {
t.advance();
return QuotientExpression.scan(t, E1);
}
return E1;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = MinusExpression.scan(t);
if (t.next() == '*' && t.nextnext() != '*') {
t.advance();
return scan(t, new ProductExpression(E, E1));
} else if (t.next() == '/') {
t.advance();
return QuotientExpression.scan(t, new ProductExpression(E, E1));
}
return new ProductExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
return E1.getValue() * E2.getValue();
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "*" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
}
/**
* E-E
*/
class DifferenceExpression extends BasicExpression {
BasicExpression E1, E2;
public DifferenceExpression(final BasicExpression e1,
final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = ProductExpression.scan(t);
if (t.next() == '+') {
t.advance();
return SumExpression.scan(t, new DifferenceExpression(E, E1));
} else if (t.next() == '-') {
t.advance();
return scan(t, new DifferenceExpression(E, E1));
}
return new DifferenceExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
return E1.getValue() - E2.getValue();
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "-" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
}
/**
* E+E
*/
class SumExpression extends BasicExpression {
BasicExpression E1, E2;
public SumExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = ProductExpression.scan(t);
if (t.next() == '+') {
t.advance();
return scan(t, E1);
} else if (t.next() == '-') {
t.advance();
return DifferenceExpression.scan(t, E1);
}
return E1;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = ProductExpression.scan(t);
if (t.next() == '+') {
t.advance();
return scan(t, new SumExpression(E, E1));
} else if (t.next() == '-') {
t.advance();
return DifferenceExpression.scan(t, new SumExpression(E, E1));
}
return new SumExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
return E1.getValue() + E2.getValue();
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "+" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
}
/**
* Diverse Vegleiche.
*/
class CompareExpression extends BasicExpression {
BasicExpression E1, E2;
int Operator;
final static int LESS = 1, LESSEQUAL = 2, GREATER = 3, GREATEREQUAL = 4,
EQUAL = 5, ABOUTEQUAL = 6;
public CompareExpression(final BasicExpression e1,
final BasicExpression e2, final int op) {
E1 = e1;
E2 = e2;
Operator = op;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = SumExpression.scan(t);
final char c = t.next();
int op = 0;
if (c == '<') {
t.advance();
if (t.next(true) == '=') {
op = LESSEQUAL;
t.advance();
} else {
op = LESS;
}
} else if (c == '>') {
t.advance();
if (t.next(true) == '=') {
op = GREATEREQUAL;
t.advance();
} else {
op = GREATER;
}
} else if (c == '=') {
t.advance();
if (t.next(true) == '=') {
t.advance();
}
op = EQUAL;
} else if (c == '~') {
t.advance();
if (t.next(true) == '=') {
t.advance();
}
op = ABOUTEQUAL;
} else {
return E1;
}
final BasicExpression E2 = SumExpression.scan(t);
return new CompareExpression(E1, E2, op);
}
@Override
public double getValue() throws ConstructionException {
switch (Operator) {
case LESS:
return logical(E1.getValue() < E2.getValue());
case LESSEQUAL:
return logical(E1.getValue() <= E2.getValue());
case GREATER:
return logical(E1.getValue() > E2.getValue());
case GREATEREQUAL:
return logical(E1.getValue() >= E2.getValue());
case EQUAL:
// return logical(E1.getValue()==E2.getValue());
return logical(Math.abs(E1.getValue() - E2.getValue()) < 1e-14);
case ABOUTEQUAL:
return logical(Math.abs(E1.getValue() - E2.getValue()) < 1e-10);
}
return 0.0;
}
public double logical(final boolean flag) {
if (flag) {
return 1.0;
} else {
return 0.0;
}
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
switch (Operator) {
case LESS:
return E1 + "<" + E2;
case LESSEQUAL:
return E1 + "<=" + E2;
case GREATER:
return E1 + ">" + E2;
case GREATEREQUAL:
return E1 + ">=" + E2;
case EQUAL:
return E1 + "==" + E2;
case ABOUTEQUAL:
return E1 + "~=" + E2;
}
return "";
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
@Override
public boolean isLogical() {
return true;
}
}
/**
* ! CE
*/
class NotExpression extends BasicExpression {
BasicExpression E1;
public NotExpression(final BasicExpression e1) {
E1 = e1;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
if (t.next() != '!') {
return CompareExpression.scan(t);
}
t.advance();
final BasicExpression E1 = CompareExpression.scan(t);
return new NotExpression(E1);
}
@Override
public double getValue() throws ConstructionException {
if (E1.getValue() == 0.0) {
return 1.0;
} else {
return 0.0;
}
}
@Override
public void translate() {
E1.translate();
}
@Override
public String toString() {
return "!" + E1;
}
@Override
public void reset() {
E1.reset();
}
@Override
public boolean isLogical() {
return true;
}
}
/**
* /* E & E
*/
class AndExpression extends BasicExpression {
BasicExpression E1, E2;
public AndExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = NotExpression.scan(t);
if (t.next() == '&') {
t.advance();
if (t.next(true) == '&') {
t.advance();
}
return scan(t, E1);
}
return E1;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = NotExpression.scan(t);
if (t.next() == '&') {
t.advance();
return scan(t, new AndExpression(E, E1));
}
return new AndExpression(E, E1);
}
@Override
public double getValue() throws ConstructionException {
if (E1.getValue() != 0.0 && E2.getValue() != 0.0) {
return 1.0;
} else {
return 0.0;
}
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "&&" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
@Override
public boolean isLogical() {
return true;
}
}
/**
* E | E
*/
class OrExpression extends BasicExpression {
BasicExpression E1, E2;
public OrExpression(final BasicExpression e1, final BasicExpression e2) {
E1 = e1;
E2 = e2;
}
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
final BasicExpression E1 = AndExpression.scan(t);
if (t.next() == '|') {
t.advance();
if (t.next(true) == '|') {
t.advance();
}
return scan(t, E1);
}
return E1;
}
public static BasicExpression scan(final ExpressionText t,
final BasicExpression E) throws ConstructionException {
final BasicExpression E1 = AndExpression.scan(t);
if (t.next() == '|') {
t.advance();
if (t.next(true) == '|') {
t.advance();
}
return scan(t, new OrExpression(E, E1));
}
return new OrExpression(E, E1);
}
@Override
//suppression de l'évaluation paresseuse par Patrice pour un ExecuteMacro Expression-compatible
public double getValue() throws ConstructionException {
try {
if (E1.getValue() == 1.0) return 1.0;
} catch (Exception e) {}
try {
if (E2.getValue() == 1.0) return 1.0;
} catch (Exception e) {}
if (E1.getValue() != 1.0 && E2.getValue() != 1.0) {return 0.0;} else {return 1.0;}
}
@Override
public void translate() {
E1.translate();
E2.translate();
}
@Override
public String toString() {
return E1 + "||" + E2;
}
@Override
public void reset() {
E1.reset();
E2.reset();
}
@Override
public boolean isLogical() {
return true;
}
}
class TopExpression extends BasicExpression {
public static BasicExpression scan(final ExpressionText t)
throws ConstructionException {
return OrExpression.scan(t);
}
}
public class Expression {
String S;
BasicExpression E;
boolean Valid;
String ErrorText;
DepList DL;
double Value;
boolean HasDoubleValue = false;
boolean ForcePlus = false;
/**
* Create a new expression
*
* @param s
* expression string
* @param c
* construction to search for objects
* @param o
* "this" object
* @param var
* variable names used in the referring object
* @param nocircles
* prevent circular exressions
*/
public Expression(String s, final Construction c,
final ConstructionObject o, final String var[],
final boolean nocircles) {
if (s.startsWith("+")) {
ForcePlus = true;
s = s.substring(1);
}
S = s;
DL = new DepList();
try {
final ExpressionText t = new ExpressionText(s, c, o, DL, nocircles);
t.setVar(var);
E = TopExpression.scan(t);
if (t.next() != 0) {
throw new ConstructionException(Global.name("exception.superfluous"));
}
Valid = true;
} catch (final Exception e) {
Valid = false;
ErrorText = (e.toString());
// e.printStackTrace();
}
}
public Expression(final String s, final Construction c,
final ConstructionObject o, final String var[]) {
this(s, c, o, var, false);
}
public Expression(final String s, final Construction c,
final ConstructionObject o) {
this(s, c, o, null, false);
}
public boolean isValid() {
return Valid;
}
public String getErrorText() {
return ErrorText;
}
public double getValue() throws ConstructionException {
if (HasDoubleValue) {
return Value;
}
if (!Valid) {
throw new ConstructionException(Global.name("exception.expression"));
}
final double x = E.getValue();
if (Double.isNaN(x) || Double.isInfinite(x)) {
throw new ConstructionException(Global.name("exception.value"));
}
return x;
}
public void setValue(final double x) {
HasDoubleValue = true;
ForcePlus = false;
DL = new DepList();
Value = x;
}
@Override
public String toString() {
if (HasDoubleValue) {
return "" + Value;
}
if (Valid) {
return E.toString();
} else {
return S;
}
}
public DepList getDepList() {
return DL;
}
public void translate() {
E.translate();
DL.translate();
}
public boolean isNumber() {
return HasDoubleValue || E.isNumber();
}
public void reset() {
if (E != null && Valid) {
E.reset();
}
}
public boolean isForcePlus() {
return ForcePlus;
}
public void setForcePlus(final boolean flag) {
ForcePlus = flag;
}
public ConstructionObject getObject() {
if (E instanceof ObjectExpression) {
return ((ObjectExpression) E).getObject();
} else {
return null;
}
}
/**
* Add the objects this expression depends on to the static dependency list
* of the current object.
*/
public void addDep(final ConstructionObject o) {
final Enumeration e = getDepList().elements();
while (e.hasMoreElements()) {
ConstructionObject.DL.add((ConstructionObject) e.nextElement());
}
}
}