new plotter
This commit is contained in:
parent
93c5e2a093
commit
b60b576433
@ -105,20 +105,6 @@
|
|||||||
<artifactId>simple-xml</artifactId>
|
<artifactId>simple-xml</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>achartengine</groupId>
|
|
||||||
<artifactId>achartengine</artifactId>
|
|
||||||
<version>0.7.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>arity</groupId>
|
|
||||||
<artifactId>arity</artifactId>
|
|
||||||
<version>2.1.6</version>
|
|
||||||
<scope>system</scope>
|
|
||||||
<systemPath>${project.basedir}/misc/lib/arity-2.1.6.jar</systemPath>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>admob</groupId>
|
<groupId>admob</groupId>
|
||||||
<artifactId>admob</artifactId>
|
<artifactId>admob</artifactId>
|
||||||
|
@ -12,7 +12,6 @@ import android.view.View;
|
|||||||
import com.actionbarsherlock.view.Menu;
|
import com.actionbarsherlock.view.Menu;
|
||||||
import com.actionbarsherlock.view.MenuInflater;
|
import com.actionbarsherlock.view.MenuInflater;
|
||||||
import com.actionbarsherlock.view.MenuItem;
|
import com.actionbarsherlock.view.MenuItem;
|
||||||
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.AndroidUtils2;
|
import org.solovyev.android.AndroidUtils2;
|
||||||
@ -400,13 +399,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
this.yMax = yMax;
|
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
|
@NotNull
|
||||||
public static PlotBoundaries newInstance(double xMin, double xMax, double yMin, double yMax) {
|
public static PlotBoundaries newInstance(double xMin, double xMax, double yMin, double yMax) {
|
||||||
return new PlotBoundaries(xMin, xMax, yMin, yMax);
|
return new PlotBoundaries(xMin, xMax, yMin, yMax);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// Copyright (C) 2009-2010 Mihai Preda
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator.plot;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +8,6 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Scroller;
|
import android.widget.Scroller;
|
||||||
import android.widget.ZoomButtonsController;
|
import android.widget.ZoomButtonsController;
|
||||||
import org.javia.arity.Function;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
@ -151,19 +148,19 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||||
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<ArityPlotFunction>emptyList());
|
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<PlotFunction>emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
public void setPlotFunctions(@NotNull List<PlotFunction> plotFunctions) {
|
||||||
|
|
||||||
for (ArityPlotFunction functionPlotDef : functionPlotDefs) {
|
for (PlotFunction plotFunction : plotFunctions) {
|
||||||
final int arity = functionPlotDef.getFunction().arity();
|
final int arity = plotFunction.getXyFunction().getArity();
|
||||||
if (arity != 0 && arity != 1) {
|
if (arity != 0 && arity != 1) {
|
||||||
throw new IllegalArgumentException("Function must have arity 0 or 1 for 2d plot!");
|
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();
|
clearAllGraphs();
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@ -200,10 +197,6 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
drawGraph(canvas);
|
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
|
// 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) {
|
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);
|
return up * up / (dx * dx + dy * dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeGraph(@NotNull Function function,
|
private void computeGraph(@NotNull XyFunction f,
|
||||||
float xMin,
|
float xMin,
|
||||||
float xMax,
|
float xMax,
|
||||||
float yMin,
|
float yMin,
|
||||||
float yMax,
|
float yMax,
|
||||||
@NotNull GraphData graph) {
|
@NotNull GraphData graph) {
|
||||||
if (function.arity() == 0) {
|
if (f.getArity() == 0) {
|
||||||
final float v = (float) function.eval();
|
final float v = (float) f.eval();
|
||||||
graph.clear();
|
graph.clear();
|
||||||
graph.push(xMin, v);
|
graph.push(xMin, v);
|
||||||
graph.push(xMax, v);
|
graph.push(xMax, v);
|
||||||
@ -249,7 +242,7 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (graph.empty()) {
|
if (graph.empty()) {
|
||||||
graph.push(xMin, eval(function, xMin));
|
graph.push(xMin, (float)f.eval(xMin));
|
||||||
}
|
}
|
||||||
|
|
||||||
final float ratio = getRatio();
|
final float ratio = getRatio();
|
||||||
@ -270,7 +263,7 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
}
|
}
|
||||||
if (next.empty()) {
|
if (next.empty()) {
|
||||||
float x = leftX + maxStep;
|
float x = leftX + maxStep;
|
||||||
next.push(x, eval(function, x));
|
next.push(x, (float) f.eval(x));
|
||||||
++nEval;
|
++nEval;
|
||||||
}
|
}
|
||||||
rightX = next.topX();
|
rightX = next.topX();
|
||||||
@ -283,7 +276,7 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
|
|
||||||
float dx = rightX - leftX;
|
float dx = rightX - leftX;
|
||||||
float middleX = (leftX + rightX) / 2;
|
float middleX = (leftX + rightX) / 2;
|
||||||
float middleY = eval(function, middleX);
|
float middleY = (float) f.eval(middleX);
|
||||||
++nEval;
|
++nEval;
|
||||||
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
||||||
if (dx < minStep) {
|
if (dx < minStep) {
|
||||||
@ -482,20 +475,20 @@ public class CalculatorGraph2dView extends View implements GraphView {
|
|||||||
{
|
{
|
||||||
//GRAPH
|
//GRAPH
|
||||||
|
|
||||||
final List<ArityPlotFunction> functionPlotDefs = graphViewHelper.getFunctionPlotDefs();
|
final List<PlotFunction> functionPlotDefs = graphViewHelper.getFunctionPlotDefs();
|
||||||
|
|
||||||
// create path once
|
// create path once
|
||||||
final Path path = new Path();
|
final Path path = new Path();
|
||||||
|
|
||||||
for (int i = 0; i < functionPlotDefs.size(); i++) {
|
for (int i = 0; i < functionPlotDefs.size(); i++) {
|
||||||
final ArityPlotFunction fpd = functionPlotDefs.get(i);
|
final PlotFunction fpd = functionPlotDefs.get(i);
|
||||||
computeGraph(fpd.getFunction(), xMin, xMax, lastYMin, lastYMax, graphs.get(i));
|
computeGraph(fpd.getXyFunction(), xMin, xMax, lastYMin, lastYMax, graphs.get(i));
|
||||||
|
|
||||||
graphToPath(graphs.get(i), path);
|
graphToPath(graphs.get(i), path);
|
||||||
|
|
||||||
path.transform(matrix);
|
path.transform(matrix);
|
||||||
|
|
||||||
AbstractCalculatorPlotFragment.applyToPaint(fpd.getLineDef(), paint);
|
AbstractCalculatorPlotFragment.applyToPaint(fpd.getPlotLineDef(), paint);
|
||||||
|
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,10 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.R;
|
import org.solovyev.android.calculator.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: serso
|
* User: serso
|
||||||
* Date: 12/30/12
|
* Date: 12/30/12
|
||||||
@ -44,28 +38,6 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
|
|||||||
graphContainer.removeView((View) graphView);
|
graphContainer.removeView((View) graphView);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ArityPlotFunction> arityFunctions = new ArrayList<ArityPlotFunction>();
|
|
||||||
|
|
||||||
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() ) {
|
if ( plotData.isPlot3d() ) {
|
||||||
graphView = new Graph3dView(getActivity());
|
graphView = new Graph3dView(getActivity());
|
||||||
} else {
|
} else {
|
||||||
@ -74,7 +46,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
|
|||||||
|
|
||||||
graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
|
graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
|
||||||
//graphView.setXRange((float)plotBoundaries.getXMin(), (float)plotBoundaries.getXMax());
|
//graphView.setXRange((float)plotBoundaries.getXMin(), (float)plotBoundaries.getXMax());
|
||||||
graphView.setFunctionPlotDefs(arityFunctions);
|
graphView.setPlotFunctions(plotData.getFunctions());
|
||||||
|
|
||||||
graphContainer.addView((View) graphView);
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package org.solovyev.android.calculator.plot;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import org.javia.arity.Function;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
@ -92,9 +91,9 @@ class Graph3d {
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(@NotNull GL11 gl, @NotNull ArityPlotFunction fpd, float zoom) {
|
public void update(@NotNull GL11 gl, @NotNull PlotFunction fpd, float zoom) {
|
||||||
final Function function = fpd.getFunction();
|
final XyFunction function = fpd.getXyFunction();
|
||||||
final PlotLineDef lineDef = fpd.getLineDef();
|
final PlotLineDef lineDef = fpd.getPlotLineDef();
|
||||||
final int NTICK = useHighQuality3d ? 5 : 0;
|
final int NTICK = useHighQuality3d ? 5 : 0;
|
||||||
|
|
||||||
final float size = 4 * zoom;
|
final float size = 4 * zoom;
|
||||||
@ -230,8 +229,8 @@ class Graph3d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float fillFunctionPolygonVertices(Function function, float size, float[] vertices) {
|
private float fillFunctionPolygonVertices(XyFunction function, float size, float[] vertices) {
|
||||||
final int arity = function.arity();
|
final int arity = function.getArity();
|
||||||
|
|
||||||
final float minX = -size;
|
final float minX = -size;
|
||||||
final float maxX = size;
|
final float maxX = size;
|
||||||
|
@ -174,18 +174,19 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||||
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<ArityPlotFunction>emptyList());
|
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<PlotFunction>emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
@Override
|
||||||
for (ArityPlotFunction functionPlotDef: functionPlotDefs) {
|
public void setPlotFunctions(@NotNull List<PlotFunction> plotFunctions) {
|
||||||
final int arity = functionPlotDef.getFunction().arity();
|
for (PlotFunction plotFunction: plotFunctions) {
|
||||||
|
final int arity = plotFunction.getXyFunction().getArity();
|
||||||
if (arity != 0 && arity != 1 && arity != 2) {
|
if (arity != 0 && arity != 1 && arity != 2) {
|
||||||
throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!");
|
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;
|
zoomLevel = 1;
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa
|
|||||||
|
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef);
|
public void init(@NotNull FunctionViewDef functionViewDef);
|
||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs);
|
public void setPlotFunctions(@NotNull List<PlotFunction> plotFunctions);
|
||||||
|
|
||||||
public void onPause();
|
public void onPause();
|
||||||
public void onResume();
|
public void onResume();
|
||||||
|
@ -16,7 +16,7 @@ public class GraphViewHelper {
|
|||||||
private FunctionViewDef functionViewDef = FunctionViewDef.newDefaultInstance();
|
private FunctionViewDef functionViewDef = FunctionViewDef.newDefaultInstance();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<ArityPlotFunction> functionPlotDefs = Collections.emptyList();
|
private List<PlotFunction> functionPlotDefs = Collections.emptyList();
|
||||||
|
|
||||||
private GraphViewHelper() {
|
private GraphViewHelper() {
|
||||||
}
|
}
|
||||||
@ -28,27 +28,27 @@ public class GraphViewHelper {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static GraphViewHelper newInstance(@NotNull FunctionViewDef functionViewDef,
|
public static GraphViewHelper newInstance(@NotNull FunctionViewDef functionViewDef,
|
||||||
@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
@NotNull List<PlotFunction> plotFunctions) {
|
||||||
final GraphViewHelper result = new GraphViewHelper();
|
final GraphViewHelper result = new GraphViewHelper();
|
||||||
|
|
||||||
result.functionViewDef = functionViewDef;
|
result.functionViewDef = functionViewDef;
|
||||||
result.functionPlotDefs = Collections.unmodifiableList(functionPlotDefs);
|
result.functionPlotDefs = Collections.unmodifiableList(plotFunctions);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public GraphViewHelper copy(@NotNull List<ArityPlotFunction> newFunctionPlotDefs) {
|
public GraphViewHelper copy(@NotNull List<PlotFunction> plotFunctions) {
|
||||||
final GraphViewHelper result = new GraphViewHelper();
|
final GraphViewHelper result = new GraphViewHelper();
|
||||||
|
|
||||||
result.functionViewDef = functionViewDef;
|
result.functionViewDef = functionViewDef;
|
||||||
result.functionPlotDefs = Collections.unmodifiableList(newFunctionPlotDefs);
|
result.functionPlotDefs = Collections.unmodifiableList(plotFunctions);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ArityPlotFunction> getFunctionPlotDefs() {
|
public List<PlotFunction> getFunctionPlotDefs() {
|
||||||
return functionPlotDefs;
|
return functionPlotDefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package org.solovyev.android.calculator.plot;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,15 +11,17 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class PlotData {
|
public class PlotData {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
private List<PlotFunction> functions;
|
private List<PlotFunction> functions;
|
||||||
|
|
||||||
private boolean plot3d;
|
private boolean plot3d;
|
||||||
|
|
||||||
public PlotData(List<PlotFunction> functions, boolean plot3d) {
|
public PlotData(@NotNull List<PlotFunction> functions, boolean plot3d) {
|
||||||
this.functions = functions;
|
this.functions = functions;
|
||||||
this.plot3d = plot3d;
|
this.plot3d = plot3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public List<PlotFunction> getFunctions() {
|
public List<PlotFunction> getFunctions() {
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.common.text.StringUtils;
|
import org.solovyev.common.text.StringUtils;
|
||||||
|
|
||||||
public class XyFunction {
|
public class XyFunction implements FunctionEvaluator {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
@ -41,6 +41,9 @@ public class XyFunction {
|
|||||||
|
|
||||||
private int arity;
|
private int arity;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final FunctionEvaluator evaluator;
|
||||||
|
|
||||||
public XyFunction(@NotNull Generic expression,
|
public XyFunction(@NotNull Generic expression,
|
||||||
@Nullable Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable,
|
@Nullable Constant yVariable,
|
||||||
@ -52,8 +55,10 @@ public class XyFunction {
|
|||||||
|
|
||||||
if (imag) {
|
if (imag) {
|
||||||
this.expressionString = "Im(" + expression.toString() + ")";
|
this.expressionString = "Im(" + expression.toString() + ")";
|
||||||
|
this.evaluator = new ImaginaryEvaluator(this);
|
||||||
} else {
|
} else {
|
||||||
this.expressionString = expression.toString();
|
this.expressionString = expression.toString();
|
||||||
|
this.evaluator = new RealEvaluator(this);
|
||||||
}
|
}
|
||||||
this.xVariableName = xVariable == null ? null : xVariable.getName();
|
this.xVariableName = xVariable == null ? null : xVariable.getName();
|
||||||
this.yVariableName = yVariable == null ? null : yVariable.getName();
|
this.yVariableName = yVariable == null ? null : yVariable.getName();
|
||||||
@ -74,10 +79,26 @@ public class XyFunction {
|
|||||||
return imag;
|
return imag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getArity() {
|
public int getArity() {
|
||||||
return arity;
|
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
|
@NotNull
|
||||||
public Generic getExpression() {
|
public Generic getExpression() {
|
||||||
return expression;
|
return expression;
|
||||||
@ -113,8 +134,7 @@ public class XyFunction {
|
|||||||
return yVariableName;
|
return yVariableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (!(o instanceof XyFunction)) return false;
|
if (!(o instanceof XyFunction)) return false;
|
||||||
@ -130,4 +150,85 @@ public class XyFunction {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return id.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user