diff --git a/android-app/pom.xml b/android-app/pom.xml index b9dc5dae..c1b41ec5 100644 --- a/android-app/pom.xml +++ b/android-app/pom.xml @@ -105,20 +105,6 @@ simple-xml - - achartengine - achartengine - 0.7.1 - - - - arity - arity - 2.1.6 - system - ${project.basedir}/misc/lib/arity-2.1.6.jar - - admob admob diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java index 3582ba34..6d6990c8 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java @@ -12,7 +12,6 @@ import android.view.View; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; -import org.achartengine.renderer.XYMultipleSeriesRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.AndroidUtils2; @@ -400,13 +399,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment this.yMax = yMax; } - public PlotBoundaries(@NotNull XYMultipleSeriesRenderer renderer) { - this.xMin = renderer.getXAxisMin(); - this.yMin = renderer.getYAxisMin(); - this.xMax = renderer.getXAxisMax(); - this.yMax = renderer.getYAxisMax(); - } - @NotNull public static PlotBoundaries newInstance(double xMin, double xMax, double yMin, double yMax) { return new PlotBoundaries(xMin, xMax, yMin, yMax); diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java index 35d0c695..cdafcef8 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java @@ -1,5 +1,3 @@ -// Copyright (C) 2009-2010 Mihai Preda - package org.solovyev.android.calculator.plot; @@ -10,7 +8,6 @@ import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; import android.widget.ZoomButtonsController; -import org.javia.arity.Function; import org.jetbrains.annotations.NotNull; import java.text.DecimalFormat; @@ -151,19 +148,19 @@ public class CalculatorGraph2dView extends View implements GraphView { @Override public void init(@NotNull FunctionViewDef functionViewDef) { - this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.emptyList()); + this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.emptyList()); } - public void setFunctionPlotDefs(@NotNull List functionPlotDefs) { + public void setPlotFunctions(@NotNull List plotFunctions) { - for (ArityPlotFunction functionPlotDef : functionPlotDefs) { - final int arity = functionPlotDef.getFunction().arity(); + for (PlotFunction plotFunction : plotFunctions) { + final int arity = plotFunction.getXyFunction().getArity(); if (arity != 0 && arity != 1) { throw new IllegalArgumentException("Function must have arity 0 or 1 for 2d plot!"); } } - this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs); + this.graphViewHelper = this.graphViewHelper.copy(plotFunctions); clearAllGraphs(); invalidate(); } @@ -200,10 +197,6 @@ public class CalculatorGraph2dView extends View implements GraphView { drawGraph(canvas); } - private float eval(Function f, float x) { - return (float) f.eval(x); - } - // distance from (x,y) to the line (x1,y1) to (x2,y2), squared, multiplied by 4 /* private float distance(float x1, float y1, float x2, float y2, float x, float y) { @@ -224,14 +217,14 @@ public class CalculatorGraph2dView extends View implements GraphView { return up * up / (dx * dx + dy * dy); } - private void computeGraph(@NotNull Function function, + private void computeGraph(@NotNull XyFunction f, float xMin, float xMax, float yMin, float yMax, @NotNull GraphData graph) { - if (function.arity() == 0) { - final float v = (float) function.eval(); + if (f.getArity() == 0) { + final float v = (float) f.eval(); graph.clear(); graph.push(xMin, v); graph.push(xMax, v); @@ -249,7 +242,7 @@ public class CalculatorGraph2dView extends View implements GraphView { } } if (graph.empty()) { - graph.push(xMin, eval(function, xMin)); + graph.push(xMin, (float)f.eval(xMin)); } final float ratio = getRatio(); @@ -270,7 +263,7 @@ public class CalculatorGraph2dView extends View implements GraphView { } if (next.empty()) { float x = leftX + maxStep; - next.push(x, eval(function, x)); + next.push(x, (float) f.eval(x)); ++nEval; } rightX = next.topX(); @@ -283,7 +276,7 @@ public class CalculatorGraph2dView extends View implements GraphView { float dx = rightX - leftX; float middleX = (leftX + rightX) / 2; - float middleY = eval(function, middleX); + float middleY = (float) f.eval(middleX); ++nEval; boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY); if (dx < minStep) { @@ -482,20 +475,20 @@ public class CalculatorGraph2dView extends View implements GraphView { { //GRAPH - final List functionPlotDefs = graphViewHelper.getFunctionPlotDefs(); + final List functionPlotDefs = graphViewHelper.getFunctionPlotDefs(); // create path once final Path path = new Path(); for (int i = 0; i < functionPlotDefs.size(); i++) { - final ArityPlotFunction fpd = functionPlotDefs.get(i); - computeGraph(fpd.getFunction(), xMin, xMax, lastYMin, lastYMax, graphs.get(i)); + final PlotFunction fpd = functionPlotDefs.get(i); + computeGraph(fpd.getXyFunction(), xMin, xMax, lastYMin, lastYMax, graphs.get(i)); graphToPath(graphs.get(i), path); path.transform(matrix); - AbstractCalculatorPlotFragment.applyToPaint(fpd.getLineDef(), paint); + AbstractCalculatorPlotFragment.applyToPaint(fpd.getPlotLineDef(), paint); canvas.drawPath(path, paint); } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java index 7ebde5ab..fad8ec6b 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java @@ -4,16 +4,10 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.view.View; import android.view.ViewGroup; -import jscl.math.Generic; -import jscl.math.function.Constant; -import org.javia.arity.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.R; -import java.util.ArrayList; -import java.util.List; - /** * User: serso * Date: 12/30/12 @@ -44,28 +38,6 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { graphContainer.removeView((View) graphView); } - final List arityFunctions = new ArrayList(); - - for (PlotFunction plotFunction : plotData.getFunctions()) { - - final XyFunction xyFunction = plotFunction.getXyFunction(); - - final Generic expression = xyFunction.getExpression(); - final Constant xVariable = xyFunction.getXVariable(); - final Constant yVariable = xyFunction.getYVariable(); - - final int arity = xyFunction.getArity(); - - final Function arityFunction; - if (xyFunction.isImag()) { - arityFunction = new ImaginaryArityFunction(arity, expression, xVariable, yVariable); - } else { - arityFunction = new RealArityFunction(arity, expression, xVariable, yVariable); - } - - arityFunctions.add(ArityPlotFunction.newInstance(arityFunction, plotFunction.getPlotLineDef())); - } - if ( plotData.isPlot3d() ) { graphView = new Graph3dView(getActivity()); } else { @@ -74,7 +46,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor())); //graphView.setXRange((float)plotBoundaries.getXMin(), (float)plotBoundaries.getXMax()); - graphView.setFunctionPlotDefs(arityFunctions); + graphView.setPlotFunctions(plotData.getFunctions()); graphContainer.addView((View) graphView); } @@ -135,96 +107,4 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { ********************************************************************** */ - private static abstract class AbstractArityFunction extends Function { - - protected final int arity; - - @NotNull - protected final Generic expression; - - @Nullable - protected final Constant xVariable; - - @Nullable - protected final Constant yVariable; - - @Nullable - private Double constant = null; - - public AbstractArityFunction(int arity, - @NotNull Generic expression, - @Nullable Constant xVariable, - @Nullable Constant yVariable) { - this.arity = arity; - this.expression = expression; - this.xVariable = xVariable; - this.yVariable = yVariable; - } - - @Override - public final double eval() { - if (constant == null) { - constant = eval0(); - } - return constant; - } - - protected abstract double eval0(); - - @Override - public final int arity() { - return arity; - } - - } - - private static class RealArityFunction extends AbstractArityFunction { - - private RealArityFunction(int arity, - @NotNull Generic expression, - @Nullable Constant xVariable, - @Nullable Constant yVariable) { - super(arity, expression, xVariable, yVariable); - } - - @Override - public double eval0() { - return PlotUtils.calculatorExpression(expression).realPart(); - } - - @Override - public double eval(double x) { - return PlotUtils.calculatorExpression(expression, xVariable, x).realPart(); - } - - @Override - public double eval(double x, double y) { - return PlotUtils.calculatorExpression(expression, xVariable, x, yVariable, y).realPart(); - } - } - - private static class ImaginaryArityFunction extends AbstractArityFunction { - - private ImaginaryArityFunction(int arity, - @NotNull Generic expression, - @Nullable Constant xVariable, - @Nullable Constant yVariable) { - super(arity, expression, xVariable, yVariable); - } - - @Override - public double eval0() { - return PlotUtils.calculatorExpression(expression).imaginaryPart(); - } - - @Override - public double eval(double x) { - return PlotUtils.calculatorExpression(expression, xVariable, x).imaginaryPart(); - } - - @Override - public double eval(double x, double y) { - return PlotUtils.calculatorExpression(expression, xVariable, x, yVariable, y).imaginaryPart(); - } - } } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java index 1de16160..2f2ae959 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java @@ -3,7 +3,6 @@ package org.solovyev.android.calculator.plot; import android.graphics.Color; -import org.javia.arity.Function; import org.jetbrains.annotations.NotNull; import javax.microedition.khronos.opengles.GL10; @@ -92,9 +91,9 @@ class Graph3d { return bb; } - public void update(@NotNull GL11 gl, @NotNull ArityPlotFunction fpd, float zoom) { - final Function function = fpd.getFunction(); - final PlotLineDef lineDef = fpd.getLineDef(); + public void update(@NotNull GL11 gl, @NotNull PlotFunction fpd, float zoom) { + final XyFunction function = fpd.getXyFunction(); + final PlotLineDef lineDef = fpd.getPlotLineDef(); final int NTICK = useHighQuality3d ? 5 : 0; final float size = 4 * zoom; @@ -230,8 +229,8 @@ class Graph3d { } } - private float fillFunctionPolygonVertices(Function function, float size, float[] vertices) { - final int arity = function.arity(); + private float fillFunctionPolygonVertices(XyFunction function, float size, float[] vertices) { + final int arity = function.getArity(); final float minX = -size; final float maxX = size; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3dView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3dView.java index b27b6179..644718bf 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3dView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3dView.java @@ -174,18 +174,19 @@ public class Graph3dView extends GLView implements GraphView { @Override public void init(@NotNull FunctionViewDef functionViewDef) { - this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.emptyList()); + this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.emptyList()); } - public void setFunctionPlotDefs(@NotNull List functionPlotDefs) { - for (ArityPlotFunction functionPlotDef: functionPlotDefs) { - final int arity = functionPlotDef.getFunction().arity(); + @Override + public void setPlotFunctions(@NotNull List plotFunctions) { + for (PlotFunction plotFunction: plotFunctions) { + final int arity = plotFunction.getXyFunction().getArity(); if (arity != 0 && arity != 1 && arity != 2) { throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!"); } } - this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs); + this.graphViewHelper = this.graphViewHelper.copy(plotFunctions); zoomLevel = 1; isDirty = true; } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java index d9aab0a7..48bc640d 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java @@ -12,7 +12,7 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa public void init(@NotNull FunctionViewDef functionViewDef); - public void setFunctionPlotDefs(@NotNull List functionPlotDefs); + public void setPlotFunctions(@NotNull List plotFunctions); public void onPause(); public void onResume(); diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphViewHelper.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphViewHelper.java index 7a5bb33c..a6daadb6 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphViewHelper.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphViewHelper.java @@ -16,7 +16,7 @@ public class GraphViewHelper { private FunctionViewDef functionViewDef = FunctionViewDef.newDefaultInstance(); @NotNull - private List functionPlotDefs = Collections.emptyList(); + private List functionPlotDefs = Collections.emptyList(); private GraphViewHelper() { } @@ -28,27 +28,27 @@ public class GraphViewHelper { @NotNull public static GraphViewHelper newInstance(@NotNull FunctionViewDef functionViewDef, - @NotNull List functionPlotDefs) { + @NotNull List plotFunctions) { final GraphViewHelper result = new GraphViewHelper(); result.functionViewDef = functionViewDef; - result.functionPlotDefs = Collections.unmodifiableList(functionPlotDefs); + result.functionPlotDefs = Collections.unmodifiableList(plotFunctions); return result; } @NotNull - public GraphViewHelper copy(@NotNull List newFunctionPlotDefs) { + public GraphViewHelper copy(@NotNull List plotFunctions) { final GraphViewHelper result = new GraphViewHelper(); result.functionViewDef = functionViewDef; - result.functionPlotDefs = Collections.unmodifiableList(newFunctionPlotDefs); + result.functionPlotDefs = Collections.unmodifiableList(plotFunctions); return result; } @NotNull - public List getFunctionPlotDefs() { + public List getFunctionPlotDefs() { return functionPlotDefs; } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java deleted file mode 100644 index 96ec1292..00000000 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (c) 2009-2011. Created by serso aka se.solovyev. - * For more information, please, contact se.solovyev@gmail.com - * or visit http://se.solovyev.org - */ - -package org.solovyev.android.calculator.plot; - -import jscl.math.Expression; -import jscl.math.Generic; -import jscl.math.JsclInteger; -import jscl.math.NumericWrapper; -import jscl.math.function.Constant; -import jscl.math.numeric.Complex; -import jscl.math.numeric.Numeric; -import jscl.math.numeric.Real; -import org.achartengine.chart.CubicLineChart; -import org.achartengine.chart.PointStyle; -import org.achartengine.chart.ScatterChart; -import org.achartengine.chart.XYChart; -import org.achartengine.model.XYMultipleSeriesDataset; -import org.achartengine.renderer.BasicStroke; -import org.achartengine.renderer.XYMultipleSeriesRenderer; -import org.achartengine.renderer.XYSeriesRenderer; -import org.achartengine.util.MathHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.solovyev.android.calculator.Locator; -import org.solovyev.android.calculator.R; -import org.solovyev.common.msg.MessageType; -import org.solovyev.common.text.StringUtils; - -import java.util.Arrays; - -/** - * User: serso - * Date: 12/5/11 - * Time: 8:58 PM - */ -public final class PlotUtils { - - private static final double MAX_Y_DIFF = 1; - private static final double MAX_X_DIFF = 1; - static final int DEFAULT_NUMBER_OF_STEPS = 100; - - // not intended for instantiation - private PlotUtils() { - throw new AssertionError(); - } - - public static boolean addXY(double minValue, - double maxValue, - @NotNull Generic expression, - @Nullable Constant variable, - @NotNull MyXYSeries realSeries, - @Nullable MyXYSeries imagSeries, - boolean addExtra, - int numberOfSteps) { - - boolean imagExists = false; - - double min = Math.min(minValue, maxValue); - double max = Math.max(minValue, maxValue); - double dist = max - min; - if (addExtra) { - min = min - dist; - max = max + dist; - } - - final double eps = 0.000000001; - - final double defaultStep = Math.max(dist / numberOfSteps, eps); - double step = defaultStep; - - final Point real = new Point(); - final Point imag = new Point(); - - double x = min; - - while (x <= max) { - - boolean needToCalculateRealY = realSeries.needToAdd(step, x); - - if (needToCalculateRealY) { - final Complex c = variable == null ? calculatorExpression(expression) : calculatorExpression(expression, variable, x); - Double y = prepareY(c.realPart()); - - if (y != null) { - real.moveToNextPoint(x, y); - addSingularityPoint(realSeries, real); - realSeries.add(x, y); - } - - boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x); - if (needToCalculateImagY) { - y = prepareY(c.imaginaryPart()); - if (y != null) { - imag.moveToNextPoint(x, y); - addSingularityPoint(imagSeries, imag); - imagSeries.add(x, y); - } - if (c.imaginaryPart() != 0d) { - imagExists = true; - } - } - } else { - boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x); - if (needToCalculateImagY) { - final Complex c = variable == null ? calculatorExpression(expression) : calculatorExpression(expression, variable, x); - Double y = prepareY(c.imaginaryPart()); - if (y != null) { - imag.moveToNextPoint(x, y); - addSingularityPoint(imagSeries, imag); - imagSeries.add(x, y); - } - if (c.imaginaryPart() != 0d) { - imagExists = true; - } - } - } - - step = updateStep(real, step, defaultStep / 2); - - x += step; - } - - return imagExists; - } - - @NotNull - static String getImagFunctionName(@Nullable Constant variable) { - if (variable != null) { - return "g(" + variable.getName() + ")" + " = " + "Im(ƒ(" + variable.getName() + "))"; - } else { - return "g = Im(ƒ)"; - } - } - - @NotNull - private static String getRealFunctionName(@NotNull Generic expression, @Nullable Constant variable) { - if (variable != null) { - return "ƒ(" + variable.getName() + ")" + " = " + expression.toString(); - } else { - return "ƒ = " + expression.toString(); - } - } - - @NotNull - static XYChart prepareChart(final double minValue, - final double maxValue, - @NotNull final Generic expression, - @Nullable final Constant variable, - int bgColor, - boolean interpolate, - int realLineColor, - int imagLineColor) { - final MyXYSeries realSeries = new MyXYSeries(getRealFunctionName(expression, variable), DEFAULT_NUMBER_OF_STEPS * 2); - final MyXYSeries imagSeries = new MyXYSeries(getImagFunctionName(variable), DEFAULT_NUMBER_OF_STEPS * 2); - - boolean imagExists = addXY(minValue, maxValue, expression, variable, realSeries, imagSeries, false, DEFAULT_NUMBER_OF_STEPS); - - final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset(); - data.addSeries(realSeries); - if (imagExists) { - data.addSeries(imagSeries); - } - - final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(); - renderer.setShowGrid(true); - renderer.setXTitle(variable != null ? variable.getName() : null); - if (variable != null) { - renderer.setYTitle("f(" + variable.getName() + ")"); - } else { - renderer.setYTitle("f"); - } - renderer.setChartTitleTextSize(25); - renderer.setAxisTitleTextSize(25); - renderer.setLabelsTextSize(25); - renderer.setLegendTextSize(25); - renderer.setMargins(new int[]{25, 25, 25, 25}); - renderer.setApplyBackgroundColor(true); - renderer.setBackgroundColor(bgColor); - renderer.setMarginsColor(bgColor); - - renderer.setZoomEnabled(true); - renderer.setZoomButtonsVisible(true); - - renderer.addSeriesRenderer(createCommonRenderer(realLineColor)); - if (imagExists) { - renderer.addSeriesRenderer(createImagRenderer(imagLineColor)); - } - - if (interpolate) { - return new CubicLineChart(data, renderer, 0.1f); - } else { - return new ScatterChart(data, renderer); - } - } - - static XYSeriesRenderer createImagRenderer(int color) { - final XYSeriesRenderer imagRenderer = createCommonRenderer(color); - imagRenderer.setStroke(BasicStroke.DASHED); - return imagRenderer; - } - - @NotNull - private static XYSeriesRenderer createCommonRenderer(int color) { - final XYSeriesRenderer renderer = new XYSeriesRenderer(); - renderer.setFillPoints(true); - renderer.setPointStyle(PointStyle.CIRCLE); - renderer.setLineWidth(3); - renderer.setColor(color); - renderer.setStroke(BasicStroke.SOLID); - return renderer; - } - - static void handleArithmeticException(@NotNull ArithmeticException e, @NotNull AbstractCalculatorPlotFragment calculatorPlotFragment) { - String message = e.getLocalizedMessage(); - if (StringUtils.isEmpty(message)) { - message = e.getMessage(); - } - Locator.getInstance().getNotifier().showMessage(R.string.arithmetic_error_while_plot, MessageType.error, Arrays.asList(message)); - calculatorPlotFragment.onError(); - } - - private static class Point { - private static final double DEFAULT = Double.MIN_VALUE; - - private double x0 = DEFAULT; - private double x1 = DEFAULT; - private double x2 = DEFAULT; - - private double y0 = DEFAULT; - private double y1 = DEFAULT; - private double y2 = DEFAULT; - - private Point() { - } - - public void moveToNextPoint(double x, double y) { - if ( this.x2 == x ) { - return; - } - - this.x0 = this.x1; - this.x1 = this.x2; - this.x2 = x; - - this.y0 = this.y1; - this.y1 = this.y2; - this.y2 = y; - } - - public boolean isFullyDefined() { - return x0 != DEFAULT && x1 != DEFAULT && x2 != DEFAULT && y0 != DEFAULT && y1 != DEFAULT && y2 != DEFAULT; - } - - public double getDx2() { - return x2 - x1; - } - - public double getAbsDx2() { - if ( x2 > x1 ) { - return Math.abs(x2 - x1); - } else { - return Math.abs(x1 - x2); - } - } - - public double getAbsDx1() { - if ( x1 > x0 ) { - return Math.abs(x1 - x0); - } else { - return Math.abs(x0 - x1); - } - } - - public double getAbsDy1() { - if ( y1 > y0 ) { - return Math.abs(y1 - y0); - } else { - return Math.abs(y0 - y1); - } - } - - public double getAbsDy2() { - if ( y2 > y1 ) { - return Math.abs(y2 - y1); - } else { - return Math.abs(y1 - y2); - } - } - - public double getX0() { - return x0; - } - - public double getX1() { - return x1; - } - - public double getX2() { - return x2; - } - - public boolean isX2Defined() { - return x2 != DEFAULT; - } - - public double getY0() { - return y0; - } - - public double getY1() { - return y1; - } - - public double getY2() { - return y2; - } - - public void clearHistory () { - this.x0 = DEFAULT; - this.x1 = DEFAULT; - this.y0 = DEFAULT; - this.y1 = DEFAULT; - } - - public double getAbsDyDx2() { - double dx2 = this.getAbsDx2(); - double dy2 = this.getAbsDy2(); - return dy2 / dx2; - } - - public double getAbsDyDx1() { - double dx1 = this.getAbsDx1(); - double dy1 = this.getAbsDy1(); - return dy1 / dx1; - } - - public double getDyDx1() { - double result = getAbsDyDx1(); - return y1 > y0 ? result : -result; - } - - public double getDyDx2() { - double result = getAbsDyDx2(); - return y2 > y1 ? result : -result; - } - - @Override - public String toString() { - return "Point{" + - "x0=" + x0 + - ", x1=" + x1 + - ", x2=" + x2 + - ", y0=" + y0 + - ", y1=" + y1 + - ", y2=" + y2 + - '}'; - } - } - - private static double updateStep(@NotNull Point real, - double step, - double eps) { - if ( !real.isFullyDefined() ) { - return step; - } else { - double dydx2 = real.getAbsDyDx2(); - double dydx1 = real.getAbsDyDx1(); - - double k = dydx2 / dydx1; - - if ( k > 1 ) { - step = step / k; - } else if ( k > 0 ) { - step = step * k; - } - - return Math.max(step, eps); - } - } - - @NotNull - public static Complex calculatorExpression(@NotNull Generic expression) { - try { - return unwrap(expression.numeric()); - } catch (RuntimeException e) { - return NaN; - } - } - - @NotNull - public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x) { - try { - return unwrap(expression.substitute(xVar, Expression.valueOf(x)).numeric()); - } catch (RuntimeException e) { - return NaN; - } - } - - @NotNull - public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x, @NotNull Constant yVar, double y) { - try { - Generic tmp = expression.substitute(xVar, Expression.valueOf(x)); - tmp = tmp.substitute(yVar, Expression.valueOf(y)); - return unwrap(tmp.numeric()); - } catch (RuntimeException e) { - return NaN; - } - } - - public static void addSingularityPoint(@NotNull MyXYSeries series, - @NotNull Point point) { - if (point.isFullyDefined()) { - // y or prevY should be more than 1d because if they are too small false singularity may occur (e.g., 1/0.000000000000000001) - // double dy0 = y1 - y0; - // double dx0 = x1 - x0; - // double dydx0 = dy0 / dx0; - - double dy2 = point.getAbsDy2(); - double dx2 = point.getAbsDx2(); - //double dx1 = x2 - x1; - // double dydx1 = dy2 / dx1; - - if ( dy2 > MAX_Y_DIFF && dx2 < MAX_X_DIFF && isDifferentSign(point.getY2(), point.getY1()) && isDifferentSign(point.getDyDx1(), point.getDyDx2())) { - //Log.d(CalculatorPlotActivity.class.getName(), "Singularity: " + point); - //Log.d(CalculatorPlotActivity.class.getName(), String.valueOf(prevX + Math.abs(x - prevX) / 2) + ", null"); - series.add(point.getX1() + point.getAbsDx2() / 2, MathHelper.NULL_VALUE); - point.clearHistory(); - } - } - } - - private static boolean isDifferentSign(@NotNull Double y0, @NotNull Double y1) { - return (y0 >= 0 && y1 < 0) || (y1 >= 0 && y0 < 0); - } - - @Nullable - public static Double prepareY(double y) { - if (Double.isNaN(y)) { - return null; - } else { - return y; - } - } - - private static final Complex NaN = Complex.valueOf(Double.NaN, 0d); - - @NotNull - public static Complex unwrap(@Nullable Generic numeric) { - if (numeric instanceof JsclInteger) { - return Complex.valueOf(((JsclInteger) numeric).intValue(), 0d); - } else if (numeric instanceof NumericWrapper) { - return unwrap(((NumericWrapper) numeric).content()); - } else { - return NaN; - } - } - - @NotNull - public static Complex unwrap(@Nullable Numeric content) { - if (content instanceof Real) { - return Complex.valueOf(((Real) content).doubleValue(), 0d); - } else if (content instanceof Complex) { - return ((Complex) content); - } else { - throw new ArithmeticException(); - } - } -} diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/FunctionEvaluator.java b/core/src/main/java/org/solovyev/android/calculator/plot/FunctionEvaluator.java new file mode 100644 index 00000000..ee825472 --- /dev/null +++ b/core/src/main/java/org/solovyev/android/calculator/plot/FunctionEvaluator.java @@ -0,0 +1,13 @@ +package org.solovyev.android.calculator.plot; + +/** +* User: serso +* Date: 1/18/13 +* Time: 7:44 PM +*/ +interface FunctionEvaluator { + int getArity(); + double eval(); + double eval(double x); + double eval(double x, double y); +} diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java b/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java index 2ec8c187..82ce8797 100644 --- a/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java +++ b/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java @@ -1,5 +1,7 @@ package org.solovyev.android.calculator.plot; +import org.jetbrains.annotations.NotNull; + import java.util.List; /** @@ -9,15 +11,17 @@ import java.util.List; */ public class PlotData { + @NotNull private List functions; private boolean plot3d; - public PlotData(List functions, boolean plot3d) { + public PlotData(@NotNull List functions, boolean plot3d) { this.functions = functions; this.plot3d = plot3d; } + @NotNull public List getFunctions() { return functions; } diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java b/core/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java new file mode 100644 index 00000000..62a453cd --- /dev/null +++ b/core/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator.plot; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.JsclInteger; +import jscl.math.NumericWrapper; +import jscl.math.function.Constant; +import jscl.math.numeric.Complex; +import jscl.math.numeric.Numeric; +import jscl.math.numeric.Real; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: serso + * Date: 12/5/11 + * Time: 8:58 PM + */ +public final class PlotUtils { + + // not intended for instantiation + private PlotUtils() { + throw new AssertionError(); + } + + @NotNull + public static Complex calculatorExpression(@NotNull Generic expression) { + try { + return unwrap(expression.numeric()); + } catch (RuntimeException e) { + return NaN; + } + } + + @NotNull + public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x) { + try { + return unwrap(expression.substitute(xVar, Expression.valueOf(x)).numeric()); + } catch (RuntimeException e) { + return NaN; + } + } + + @NotNull + public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x, @NotNull Constant yVar, double y) { + try { + Generic tmp = expression.substitute(xVar, Expression.valueOf(x)); + tmp = tmp.substitute(yVar, Expression.valueOf(y)); + return unwrap(tmp.numeric()); + } catch (RuntimeException e) { + return NaN; + } + } + + private static final Complex NaN = Complex.valueOf(Double.NaN, 0d); + + @NotNull + public static Complex unwrap(@Nullable Generic numeric) { + if (numeric instanceof JsclInteger) { + return Complex.valueOf(((JsclInteger) numeric).intValue(), 0d); + } else if (numeric instanceof NumericWrapper) { + return unwrap(((NumericWrapper) numeric).content()); + } else { + return NaN; + } + } + + @NotNull + public static Complex unwrap(@Nullable Numeric content) { + if (content instanceof Real) { + return Complex.valueOf(((Real) content).doubleValue(), 0d); + } else if (content instanceof Complex) { + return ((Complex) content); + } else { + throw new ArithmeticException(); + } + } +} diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/XyFunction.java b/core/src/main/java/org/solovyev/android/calculator/plot/XyFunction.java index b66f99d9..a2916602 100644 --- a/core/src/main/java/org/solovyev/android/calculator/plot/XyFunction.java +++ b/core/src/main/java/org/solovyev/android/calculator/plot/XyFunction.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.common.text.StringUtils; -public class XyFunction { +public class XyFunction implements FunctionEvaluator { /* ********************************************************************** @@ -41,6 +41,9 @@ public class XyFunction { private int arity; + @NotNull + private final FunctionEvaluator evaluator; + public XyFunction(@NotNull Generic expression, @Nullable Constant xVariable, @Nullable Constant yVariable, @@ -52,8 +55,10 @@ public class XyFunction { if (imag) { this.expressionString = "Im(" + expression.toString() + ")"; + this.evaluator = new ImaginaryEvaluator(this); } else { this.expressionString = expression.toString(); + this.evaluator = new RealEvaluator(this); } this.xVariableName = xVariable == null ? null : xVariable.getName(); this.yVariableName = yVariable == null ? null : yVariable.getName(); @@ -74,10 +79,26 @@ public class XyFunction { return imag; } + @Override public int getArity() { return arity; } + @Override + public double eval() { + return evaluator.eval(); + } + + @Override + public double eval(double x) { + return evaluator.eval(x); + } + + @Override + public double eval(double x, double y) { + return evaluator.eval(x, y); + } + @NotNull public Generic getExpression() { return expression; @@ -113,8 +134,7 @@ public class XyFunction { return yVariableName; } - - @Override + @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof XyFunction)) return false; @@ -130,4 +150,85 @@ public class XyFunction { public int hashCode() { return id.hashCode(); } + + /* + ********************************************************************** + * + * STATIC + * + ********************************************************************** + */ + + private static abstract class AbstractEvaluator implements FunctionEvaluator { + + @NotNull + protected final XyFunction xyFunction; + + @Nullable + private Double constant = null; + + public AbstractEvaluator(@NotNull XyFunction xyFunction) { + this.xyFunction = xyFunction; + } + + @Override + public final double eval() { + if (constant == null) { + constant = eval0(); + } + return constant; + } + + protected abstract double eval0(); + + @Override + public final int getArity() { + return xyFunction.getArity(); + } + + } + + private static class RealEvaluator extends AbstractEvaluator { + + private RealEvaluator(@NotNull XyFunction xyFunction) { + super(xyFunction); + } + + @Override + public double eval0() { + return PlotUtils.calculatorExpression(xyFunction.expression).realPart(); + } + + @Override + public double eval(double x) { + return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x).realPart(); + } + + @Override + public double eval(double x, double y) { + return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x, xyFunction.yVariable, y).realPart(); + } + } + + private static class ImaginaryEvaluator extends AbstractEvaluator { + + private ImaginaryEvaluator(@NotNull XyFunction xyFunction) { + super(xyFunction); + } + + @Override + public double eval0() { + return PlotUtils.calculatorExpression(xyFunction.expression).imaginaryPart(); + } + + @Override + public double eval(double x) { + return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x).imaginaryPart(); + } + + @Override + public double eval(double x, double y) { + return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x, xyFunction.yVariable, y).imaginaryPart(); + } + } }