plotting
This commit is contained in:
parent
474707c9a3
commit
5eb0df2e1e
@ -8,10 +8,8 @@ package org.solovyev.android.calculator;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -27,6 +25,8 @@ import jscl.text.ParseException;
|
|||||||
import org.achartengine.ChartFactory;
|
import org.achartengine.ChartFactory;
|
||||||
import org.achartengine.GraphicalView;
|
import org.achartengine.GraphicalView;
|
||||||
import org.achartengine.chart.LineChart;
|
import org.achartengine.chart.LineChart;
|
||||||
|
import org.achartengine.chart.PointStyle;
|
||||||
|
import org.achartengine.chart.XYChart;
|
||||||
import org.achartengine.model.Point;
|
import org.achartengine.model.Point;
|
||||||
import org.achartengine.model.XYMultipleSeriesDataset;
|
import org.achartengine.model.XYMultipleSeriesDataset;
|
||||||
import org.achartengine.model.XYSeries;
|
import org.achartengine.model.XYSeries;
|
||||||
@ -36,6 +36,7 @@ import org.achartengine.renderer.XYSeriesRenderer;
|
|||||||
import org.achartengine.tools.PanListener;
|
import org.achartengine.tools.PanListener;
|
||||||
import org.achartengine.tools.ZoomEvent;
|
import org.achartengine.tools.ZoomEvent;
|
||||||
import org.achartengine.tools.ZoomListener;
|
import org.achartengine.tools.ZoomListener;
|
||||||
|
import org.achartengine.util.MathHelper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.common.utils.MutableObject;
|
import org.solovyev.common.utils.MutableObject;
|
||||||
@ -61,7 +62,7 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
|
|
||||||
public static final String INPUT = "org.solovyev.android.calculator.CalculatorPlotActivity_input";
|
public static final String INPUT = "org.solovyev.android.calculator.CalculatorPlotActivity_input";
|
||||||
|
|
||||||
public static final long EVAL_DELAY_MILLIS = 300;
|
public static final long EVAL_DELAY_MILLIS = 400;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The encapsulated graphical view.
|
* The encapsulated graphical view.
|
||||||
@ -74,6 +75,8 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private Constant variable;
|
private Constant variable;
|
||||||
|
|
||||||
|
private static final double MAX_Y_DIFF = Math.pow(10, 10);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -112,11 +115,13 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
graphContainer.removeView(graphicalView);
|
graphContainer.removeView(graphicalView);
|
||||||
}
|
}
|
||||||
|
|
||||||
final LineChart chart = prepareChart(minValue, maxValue, expression, variable);
|
final XYChart chart = prepareChart(minValue, maxValue, expression, variable);
|
||||||
|
|
||||||
// reverting boundaries (as in prepareChart() we add some cached values )
|
// reverting boundaries (as in prepareChart() we add some cached values )
|
||||||
chart.getRenderer().setXAxisMin(DEFAULT_MIN_NUMBER);
|
chart.getRenderer().setXAxisMin(DEFAULT_MIN_NUMBER);
|
||||||
|
chart.getRenderer().setYAxisMin(DEFAULT_MIN_NUMBER);
|
||||||
chart.getRenderer().setXAxisMax(DEFAULT_MAX_NUMBER);
|
chart.getRenderer().setXAxisMax(DEFAULT_MAX_NUMBER);
|
||||||
|
chart.getRenderer().setYAxisMax(DEFAULT_MAX_NUMBER);
|
||||||
graphicalView = new GraphicalView(this, chart);
|
graphicalView = new GraphicalView(this, chart);
|
||||||
graphicalView.addZoomListener(new ZoomListener() {
|
graphicalView.addZoomListener(new ZoomListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -140,7 +145,7 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
graphContainer.addView(graphicalView);
|
graphContainer.addView(graphicalView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDataSets(@NotNull final LineChart chart) {
|
private void updateDataSets(@NotNull final XYChart chart) {
|
||||||
pendingOperation.setObject(new Runnable() {
|
pendingOperation.setObject(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -199,7 +204,7 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final static MutableObject<Runnable> pendingOperation = new MutableObject<Runnable>();
|
private final static MutableObject<Runnable> pendingOperation = new MutableObject<Runnable>();
|
||||||
|
|
||||||
private static LineChart prepareChart(final double minValue, final double maxValue, @NotNull final Generic expression, @NotNull final Constant variable) {
|
private static XYChart prepareChart(final double minValue, final double maxValue, @NotNull final Generic expression, @NotNull final Constant variable) {
|
||||||
final XYSeries realSeries = new XYSeries(getRealFunctionName(expression, variable));
|
final XYSeries realSeries = new XYSeries(getRealFunctionName(expression, variable));
|
||||||
final XYSeries imagSeries = new XYSeries(getImagFunctionName(expression, variable));
|
final XYSeries imagSeries = new XYSeries(getImagFunctionName(expression, variable));
|
||||||
|
|
||||||
@ -212,11 +217,12 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
||||||
renderer.addSeriesRenderer(createCommonRenderer());
|
|
||||||
renderer.setShowGrid(true);
|
renderer.setShowGrid(true);
|
||||||
renderer.setXTitle(variable.getName());
|
renderer.setXTitle(variable.getName());
|
||||||
renderer.setYTitle("f(" + variable.getName() + ")");
|
renderer.setYTitle("f(" + variable.getName() + ")");
|
||||||
//renderer.setYAxisAlign(Paint.Align.CENTER, 0);
|
renderer.setChartTitleTextSize(20);
|
||||||
|
|
||||||
|
renderer.addSeriesRenderer(createCommonRenderer());
|
||||||
if (imagExists) {
|
if (imagExists) {
|
||||||
renderer.addSeriesRenderer(createImagRenderer());
|
renderer.addSeriesRenderer(createImagRenderer());
|
||||||
}
|
}
|
||||||
@ -226,19 +232,28 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
|
|
||||||
private static XYSeriesRenderer createImagRenderer() {
|
private static XYSeriesRenderer createImagRenderer() {
|
||||||
final XYSeriesRenderer imagRenderer = createCommonRenderer();
|
final XYSeriesRenderer imagRenderer = createCommonRenderer();
|
||||||
imagRenderer.setStroke(BasicStroke.DOTTED);
|
imagRenderer.setStroke(BasicStroke.DASHED);
|
||||||
|
imagRenderer.setColor(Color.DKGRAY);
|
||||||
return imagRenderer;
|
return imagRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean addXY(double minValue, double maxValue, Generic expression, Constant variable, @NotNull XYSeries realSeries, @NotNull XYSeries imagSeries) {
|
private static boolean addXY(double minValue, double maxValue, Generic expression, Constant variable, @NotNull XYSeries realSeries, @NotNull XYSeries imagSeries) {
|
||||||
boolean imagExists = false;
|
boolean imagExists = false;
|
||||||
|
|
||||||
final double min = 1.5 * Math.min(minValue, maxValue);
|
double min = Math.min(minValue, maxValue);
|
||||||
final double max = 1.5 * Math.max(minValue, maxValue);
|
double max = Math.max(minValue, maxValue);
|
||||||
|
double dist = max - min;
|
||||||
|
min = min - dist;
|
||||||
|
max = max + dist;
|
||||||
|
|
||||||
final int numberOfSteps = DEFAULT_NUMBER_OF_STEPS;
|
final int numberOfSteps = DEFAULT_NUMBER_OF_STEPS;
|
||||||
final double step = Math.max((max - min) / numberOfSteps, 0.001);
|
final double step = Math.max((max - min) / numberOfSteps, 0.000000001);
|
||||||
double x = min;
|
double x = min;
|
||||||
|
Double prevRealY = null;
|
||||||
|
Double prevX = null;
|
||||||
|
Double prevImagY = null;
|
||||||
|
double maxY = Double.NEGATIVE_INFINITY;
|
||||||
|
double minY = Double.POSITIVE_INFINITY;
|
||||||
while (x <= max) {
|
while (x <= max) {
|
||||||
|
|
||||||
boolean needToCalculateRealY = needToCalculate(realSeries, step, x);
|
boolean needToCalculateRealY = needToCalculate(realSeries, step, x);
|
||||||
@ -248,14 +263,24 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
final Complex c = unwrap(numeric);
|
final Complex c = unwrap(numeric);
|
||||||
Double y = prepareY(c.realPart());
|
Double y = prepareY(c.realPart());
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
|
//addInfPoint(realSeries, prevX, x, prevRealY, y);
|
||||||
realSeries.add(x, y);
|
realSeries.add(x, y);
|
||||||
|
maxY = Math.max(maxY, y);
|
||||||
|
minY = Math.min(minY, y);
|
||||||
|
prevRealY = y;
|
||||||
|
prevX = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean needToCalculateImagY = needToCalculate(imagSeries, step, x);
|
boolean needToCalculateImagY = needToCalculate(imagSeries, step, x);
|
||||||
if (needToCalculateImagY) {
|
if (needToCalculateImagY) {
|
||||||
y = prepareY(c.imaginaryPart());
|
y = prepareY(c.imaginaryPart());
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
|
//addInfPoint(imagSeries, prevX, x, prevImagY, y);
|
||||||
imagSeries.add(x, y);
|
imagSeries.add(x, y);
|
||||||
|
maxY = Math.max(maxY, y);
|
||||||
|
minY = Math.min(minY, y);
|
||||||
|
prevImagY = y;
|
||||||
|
prevX = x;
|
||||||
}
|
}
|
||||||
if (c.imaginaryPart() != 0d) {
|
if (c.imaginaryPart() != 0d) {
|
||||||
imagExists = true;
|
imagExists = true;
|
||||||
@ -268,7 +293,12 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
final Complex c = unwrap(numeric);
|
final Complex c = unwrap(numeric);
|
||||||
Double y = prepareY(c.imaginaryPart());
|
Double y = prepareY(c.imaginaryPart());
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
|
//addInfPoint(imagSeries, prevX, x, prevImagY, y);
|
||||||
imagSeries.add(x, y);
|
imagSeries.add(x, y);
|
||||||
|
maxY = Math.max(maxY, y);
|
||||||
|
minY = Math.min(minY, y);
|
||||||
|
prevImagY = y;
|
||||||
|
prevX = x;
|
||||||
}
|
}
|
||||||
if (c.imaginaryPart() != 0d) {
|
if (c.imaginaryPart() != 0d) {
|
||||||
imagExists = true;
|
imagExists = true;
|
||||||
@ -287,6 +317,14 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
return imagExists;
|
return imagExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addInfPoint(@NotNull XYSeries series, @Nullable Double prevX, @NotNull Double x, @Nullable Double prevY, @NotNull Double y) {
|
||||||
|
if ( prevX != null && prevY != null) {
|
||||||
|
if ( Math.abs(prevY / y) > MAX_Y_DIFF || Math.abs(y / prevY) > MAX_Y_DIFF) {
|
||||||
|
series.add( prevX + Math.abs(x - prevX) / 2, MathHelper.NULL_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean needToCalculate(@NotNull XYSeries series, double step, double x) {
|
private static boolean needToCalculate(@NotNull XYSeries series, double step, double x) {
|
||||||
boolean needToCalculateY = true;
|
boolean needToCalculateY = true;
|
||||||
for ( int i = 0; i < series.getItemCount(); i++ ){
|
for ( int i = 0; i < series.getItemCount(); i++ ){
|
||||||
@ -319,6 +357,9 @@ public class CalculatorPlotActivity extends Activity {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private static XYSeriesRenderer createCommonRenderer() {
|
private static XYSeriesRenderer createCommonRenderer() {
|
||||||
final XYSeriesRenderer renderer = new XYSeriesRenderer();
|
final XYSeriesRenderer renderer = new XYSeriesRenderer();
|
||||||
|
renderer.setFillPoints(true);
|
||||||
|
renderer.setPointStyle(PointStyle.POINT);
|
||||||
|
renderer.setLineWidth(3);
|
||||||
renderer.setColor(Color.WHITE);
|
renderer.setColor(Color.WHITE);
|
||||||
renderer.setStroke(BasicStroke.SOLID);
|
renderer.setStroke(BasicStroke.SOLID);
|
||||||
return renderer;
|
return renderer;
|
||||||
|
@ -244,7 +244,7 @@ public class CalculatorEngineTest {
|
|||||||
Assert.fail();
|
Assert.fail();
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
}
|
}
|
||||||
Assert.assertEquals("NaN", cm.evaluate(JsclOperation.numeric, "ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(100)))))))))))))))").getResult());
|
Assert.assertEquals("0.34+1.382i", cm.evaluate(JsclOperation.numeric, "ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(100)))))))))))))))").getResult());
|
||||||
try {
|
try {
|
||||||
cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos())))))))))))))))))))))))))))))))))))");
|
cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos())))))))))))))))))))))))))))))))))))");
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
|
Loading…
Reference in New Issue
Block a user