new plotter
This commit is contained in:
parent
c9770cef4b
commit
1e2b5ac830
@ -6,7 +6,9 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -21,6 +23,9 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public final class AndroidUtils2 {
|
public final class AndroidUtils2 {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static final boolean AT_LEAST_API_5 = Build.VERSION.SDK_INT >= 5;
|
||||||
|
|
||||||
private AndroidUtils2() {
|
private AndroidUtils2() {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
@ -97,4 +102,16 @@ public final class AndroidUtils2 {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getPointerCountFromMotionEvent(@NotNull MotionEvent event) {
|
||||||
|
return AT_LEAST_API_5 ? event.getPointerCount() : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getXFromMotionEvent(@NotNull MotionEvent event, int pointer) {
|
||||||
|
return AT_LEAST_API_5 ? event.getX(pointer) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getYFromMotionEvent(@NotNull MotionEvent event, int pointer) {
|
||||||
|
return AT_LEAST_API_5 ? event.getY(pointer) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,6 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
|
|||||||
activityHelper.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane);
|
activityHelper.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane);
|
||||||
activityHelper.addTab(this, CalculatorFragmentType.functions, null, R.id.main_second_pane);
|
activityHelper.addTab(this, CalculatorFragmentType.functions, null, R.id.main_second_pane);
|
||||||
activityHelper.addTab(this, CalculatorFragmentType.operators, null, R.id.main_second_pane);
|
activityHelper.addTab(this, CalculatorFragmentType.operators, null, R.id.main_second_pane);
|
||||||
activityHelper.addTab(this, CalculatorFragmentType.plotter_functions, null, R.id.main_second_pane);
|
|
||||||
activityHelper.addTab(this, CalculatorPlotActivity.getPlotterFragmentType(), null, R.id.main_second_pane);
|
activityHelper.addTab(this, CalculatorPlotActivity.getPlotterFragmentType(), null, R.id.main_second_pane);
|
||||||
activityHelper.addTab(this, CalculatorFragmentType.faq, null, R.id.main_second_pane);
|
activityHelper.addTab(this, CalculatorFragmentType.faq, null, R.id.main_second_pane);
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,7 @@ import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment;
|
|||||||
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsFragment;
|
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsFragment;
|
||||||
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
|
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
|
||||||
import org.solovyev.android.calculator.matrix.CalculatorMatrixEditFragment;
|
import org.solovyev.android.calculator.matrix.CalculatorMatrixEditFragment;
|
||||||
import org.solovyev.android.calculator.plot.CalculatorArityPlotFragment;
|
import org.solovyev.android.calculator.plot.CalculatorPlotFragment;
|
||||||
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionSettingsActivity;
|
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionSettingsActivity;
|
||||||
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionsActivity;
|
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionsActivity;
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ public enum CalculatorFragmentType {
|
|||||||
variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars),
|
variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars),
|
||||||
functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions),
|
functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions),
|
||||||
operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators),
|
operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators),
|
||||||
plotter(CalculatorArityPlotFragment.class, R.layout.cpp_plot_fragment, R.string.c_graph),
|
plotter(CalculatorPlotFragment.class, R.layout.cpp_plot_fragment, R.string.c_graph),
|
||||||
|
|
||||||
// todo serso: strings
|
// todo serso: strings
|
||||||
plotter_functions(CalculatorPlotFunctionsActivity.CalculatorPlotFunctionsFragment.class, R.layout.cpp_plot_functions_fragment, R.string.c_graph),
|
plotter_functions(CalculatorPlotFunctionsActivity.CalculatorPlotFunctionsFragment.class, R.layout.cpp_plot_functions_fragment, R.string.c_graph),
|
||||||
|
@ -393,6 +393,13 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
public PlotBoundaries() {
|
public PlotBoundaries() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PlotBoundaries(double xMin, double xMax, double yMin, double yMax) {
|
||||||
|
this.xMin = xMin;
|
||||||
|
this.xMax = xMax;
|
||||||
|
this.yMin = yMin;
|
||||||
|
this.yMax = yMax;
|
||||||
|
}
|
||||||
|
|
||||||
public PlotBoundaries(@NotNull XYMultipleSeriesRenderer renderer) {
|
public PlotBoundaries(@NotNull XYMultipleSeriesRenderer renderer) {
|
||||||
this.xMin = renderer.getXAxisMin();
|
this.xMin = renderer.getXAxisMin();
|
||||||
this.yMin = renderer.getYAxisMin();
|
this.yMin = renderer.getYAxisMin();
|
||||||
@ -400,6 +407,11 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
this.yMax = renderer.getYAxisMax();
|
this.yMax = renderer.getYAxisMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static PlotBoundaries newInstance(double xMin, double xMax, double yMin, double yMax) {
|
||||||
|
return new PlotBoundaries(xMin, xMax, yMin, yMax);
|
||||||
|
}
|
||||||
|
|
||||||
public double getXMin() {
|
public double getXMin() {
|
||||||
return xMin;
|
return xMin;
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,30 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Graph2dViewNew extends View implements GraphView {
|
public class CalculatorGraph2dView extends View implements GraphView {
|
||||||
|
|
||||||
// view width and height
|
/*
|
||||||
private int width;
|
**********************************************************************
|
||||||
private int height;
|
*
|
||||||
|
* CONSTANTS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final float TICKS_COUNT = 15;
|
||||||
|
public static final int TICK_SIZE_PXS = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* FIELDS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
// view width and height in pixels
|
||||||
|
private int widthPxs;
|
||||||
|
private int heightPxs;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Matrix matrix = new Matrix();
|
private final Matrix matrix = new Matrix();
|
||||||
@ -52,8 +71,11 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private List<GraphData> graphs = new ArrayList<GraphData>(graphViewHelper.getFunctionPlotDefs().size());
|
private List<GraphData> graphs = new ArrayList<GraphData>(graphViewHelper.getFunctionPlotDefs().size());
|
||||||
|
|
||||||
|
// current position of camera in graph coordinates
|
||||||
private float x0;
|
private float x0;
|
||||||
private float y0;
|
private float y0;
|
||||||
|
|
||||||
|
// graph width in function units (NOT screen pixels)
|
||||||
private float graphWidth = 20;
|
private float graphWidth = 20;
|
||||||
|
|
||||||
private float lastXMin;
|
private float lastXMin;
|
||||||
@ -76,12 +98,12 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private Scroller scroller;
|
private Scroller scroller;
|
||||||
|
|
||||||
public Graph2dViewNew(Context context, AttributeSet attrs) {
|
public CalculatorGraph2dView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
init(context);
|
init(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Graph2dViewNew(Context context) {
|
public CalculatorGraph2dView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
init(context);
|
init(context);
|
||||||
}
|
}
|
||||||
@ -94,30 +116,30 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
textPaint.setAntiAlias(true);
|
textPaint.setAntiAlias(true);
|
||||||
|
|
||||||
width = this.getWidth();
|
widthPxs = this.getWidth();
|
||||||
height = this.getHeight();
|
heightPxs = this.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Bitmap captureScreenshot() {
|
public Bitmap captureScreenshot() {
|
||||||
final Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
final Bitmap result = Bitmap.createBitmap(widthPxs, heightPxs, Bitmap.Config.RGB_565);
|
||||||
Canvas canvas = new Canvas(result);
|
Canvas canvas = new Canvas(result);
|
||||||
onDraw(canvas);
|
onDraw(canvas);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setXRange(float xMin, float xMax) {
|
public void setXRange(float xMin, float xMax) {
|
||||||
this.x0 = xMin + graphWidth / 2;
|
this.x0 = xMin + graphWidth / 2;
|
||||||
this.graphWidth = xMax - xMin;
|
this.graphWidth = xMax - xMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearAllGraphs() {
|
private void clearAllGraphs() {
|
||||||
for (GraphData graph : graphs) {
|
for (GraphData graph : graphs) {
|
||||||
graph.clear();
|
graph.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( graphViewHelper.getFunctionPlotDefs().size() > graphs.size() ) {
|
while (graphViewHelper.getFunctionPlotDefs().size() > graphs.size()) {
|
||||||
graphs.add(GraphData.newEmptyInstance());
|
graphs.add(GraphData.newEmptyInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +151,7 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
||||||
|
|
||||||
for (ArityPlotFunction functionPlotDef: functionPlotDefs) {
|
for (ArityPlotFunction functionPlotDef : functionPlotDefs) {
|
||||||
final int arity = functionPlotDef.getFunction().arity();
|
final int arity = functionPlotDef.getFunction().arity();
|
||||||
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!");
|
||||||
@ -141,25 +163,6 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onVisibilityChanged(boolean visible) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onZoom(boolean zoomIn) {
|
|
||||||
if (zoomIn) {
|
|
||||||
if (canZoomIn()) {
|
|
||||||
graphWidth /= 2;
|
|
||||||
invalidateGraphs();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (canZoomOut()) {
|
|
||||||
graphWidth *= 2;
|
|
||||||
invalidateGraphs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zoomController.setZoomInEnabled(canZoomIn());
|
|
||||||
zoomController.setZoomOutEnabled(canZoomOut());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +175,8 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
||||||
width = w;
|
widthPxs = w;
|
||||||
height = h;
|
heightPxs = h;
|
||||||
clearAllGraphs();
|
clearAllGraphs();
|
||||||
// points = new float[w+w];
|
// points = new float[w+w];
|
||||||
}
|
}
|
||||||
@ -183,7 +186,7 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scroller.computeScrollOffset()) {
|
if (scroller.computeScrollOffset()) {
|
||||||
final float scale = graphWidth / width;
|
final float scale = graphWidth / widthPxs;
|
||||||
x0 = scroller.getCurrX() * scale;
|
x0 = scroller.getCurrX() * scale;
|
||||||
y0 = scroller.getCurrY() * scale;
|
y0 = scroller.getCurrY() * scale;
|
||||||
if (!scroller.isFinished()) {
|
if (!scroller.isFinished()) {
|
||||||
@ -259,7 +262,7 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
graph.push(xMin, eval(function, xMin));
|
graph.push(xMin, eval(function, xMin));
|
||||||
}
|
}
|
||||||
|
|
||||||
final float scale = width / graphWidth;
|
final float scale = getRatio();
|
||||||
final float maxStep = 15.8976f / scale;
|
final float maxStep = 15.8976f / scale;
|
||||||
final float minStep = .05f / scale;
|
final float minStep = .05f / scale;
|
||||||
float ythresh = 1 / scale;
|
float ythresh = 1 / scale;
|
||||||
@ -364,20 +367,20 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final float NTICKS = 15;
|
private static float getStep(float width) {
|
||||||
|
|
||||||
private static float stepFactor(float w) {
|
|
||||||
float f = 1;
|
float f = 1;
|
||||||
while (w / f > NTICKS) {
|
while (width / f > TICKS_COUNT) {
|
||||||
f *= 10;
|
f *= 10;
|
||||||
}
|
}
|
||||||
while (w / f < NTICKS / 10) {
|
|
||||||
|
while (width / f < TICKS_COUNT / 10) {
|
||||||
f /= 10;
|
f /= 10;
|
||||||
}
|
}
|
||||||
float r = w / f;
|
|
||||||
if (r < NTICKS / 5) {
|
final float r = width / f;
|
||||||
|
if (r < TICKS_COUNT / 5) {
|
||||||
return f / 5;
|
return f / 5;
|
||||||
} else if (r < NTICKS / 2) {
|
} else if (r < TICKS_COUNT / 2) {
|
||||||
return f / 2;
|
return f / 2;
|
||||||
} else {
|
} else {
|
||||||
return f;
|
return f;
|
||||||
@ -387,13 +390,14 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
private static StringBuilder b = new StringBuilder();
|
private static StringBuilder b = new StringBuilder();
|
||||||
private static char[] buf = new char[20];
|
private static char[] buf = new char[20];
|
||||||
|
|
||||||
private static StringBuilder format(final float value) {
|
@NotNull
|
||||||
int pos = 0;
|
private static CharSequence formatTick(final float tickValue) {
|
||||||
|
/*int pos = 0;
|
||||||
boolean addDot = false;
|
boolean addDot = false;
|
||||||
|
|
||||||
final boolean negative = value < 0;
|
final boolean negative = tickValue < 0;
|
||||||
|
|
||||||
int absValue = Math.round(Math.abs(value) * 100);
|
int absValue = Math.round(Math.abs(tickValue) * 100);
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
int digit = absValue % 10;
|
int digit = absValue % 10;
|
||||||
absValue /= 10;
|
absValue /= 10;
|
||||||
@ -418,17 +422,18 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
b.setLength(0);
|
b.setLength(0);
|
||||||
b.append(buf, 0, pos);
|
b.append(buf, 0, pos);
|
||||||
b.reverse();
|
b.reverse();
|
||||||
return b;
|
return b;*/
|
||||||
|
return Float.toString(tickValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawGraph(Canvas canvas) {
|
private void drawGraph(@NotNull Canvas canvas) {
|
||||||
|
final float graphHeight = getGraphHeight();
|
||||||
|
|
||||||
final float xMin = getXMin();
|
final float xMin = getXMin();
|
||||||
final float xMax = getXMax(xMin);
|
final float xMax = getXMax(xMin);
|
||||||
|
|
||||||
float graphHeight = graphWidth * height / width;
|
final float yMin = getYMin(graphHeight);
|
||||||
float yMin = y0 - graphHeight / 2;
|
final float yMax = getYMax(graphHeight, yMin);
|
||||||
float yMax = yMin + graphHeight;
|
|
||||||
|
|
||||||
if (yMin < lastYMin || yMax > lastYMax) {
|
if (yMin < lastYMin || yMax > lastYMax) {
|
||||||
float halfGraphHeight = graphHeight / 2;
|
float halfGraphHeight = graphHeight / 2;
|
||||||
@ -445,26 +450,21 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
paint.setStyle(Paint.Style.STROKE);
|
||||||
|
|
||||||
final float scale = width / graphWidth;
|
final float ratio = getRatio();
|
||||||
|
|
||||||
float x0 = -xMin * scale;
|
float x0px = -xMin * ratio;
|
||||||
boolean drawYAxis = true;
|
if (x0px < 25) {
|
||||||
if (x0 < 25) {
|
x0px = 25;
|
||||||
x0 = 25;
|
} else if (x0px > widthPxs - 3) {
|
||||||
// drawYAxis = false;
|
x0px = widthPxs - 3;
|
||||||
} else if (x0 > width - 3) {
|
|
||||||
x0 = width - 3;
|
|
||||||
// drawYAxis = false;
|
|
||||||
}
|
|
||||||
float y0 = yMax * scale;
|
|
||||||
if (y0 < 3) {
|
|
||||||
y0 = 3;
|
|
||||||
} else if (y0 > height - 15) {
|
|
||||||
y0 = height - 15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final float tickSize = 3;
|
float y0px = yMax * ratio;
|
||||||
final float y2 = y0 + tickSize;
|
if (y0px < 3) {
|
||||||
|
y0px = 3;
|
||||||
|
} else if (y0px > heightPxs - 15) {
|
||||||
|
y0px = heightPxs - 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -473,29 +473,41 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
paint.setPathEffect(new DashPathEffect(new float[]{5, 10}, 0));
|
paint.setPathEffect(new DashPathEffect(new float[]{5, 10}, 0));
|
||||||
paint.setColor(graphViewHelper.getFunctionViewDef().getGridColor());
|
paint.setColor(graphViewHelper.getFunctionViewDef().getGridColor());
|
||||||
|
|
||||||
float step = stepFactor(graphWidth);
|
|
||||||
// Calculator.log("width " + gwidth + " step " + step);
|
|
||||||
float v = ((int) (xMin / step)) * step;
|
|
||||||
textPaint.setColor(graphViewHelper.getFunctionViewDef().getAxisLabelsColor());
|
textPaint.setColor(graphViewHelper.getFunctionViewDef().getAxisLabelsColor());
|
||||||
textPaint.setTextSize(12);
|
textPaint.setTextSize(12);
|
||||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||||
float stepScale = step * scale;
|
|
||||||
for (float x = (v - xMin) * scale; x <= width; x += stepScale, v += step) {
|
final float step = getStep(graphWidth);
|
||||||
canvas.drawLine(x, 0, x, height, paint);
|
|
||||||
if (!(-.001f < v && v < .001f)) {
|
// round xMin and init first tick
|
||||||
StringBuilder b = format(v);
|
float tick = ((int) (xMin / step)) * step;
|
||||||
canvas.drawText(b, 0, b.length(), x, y2 + 10, textPaint);
|
|
||||||
|
final float y2 = y0px + TICK_SIZE_PXS;
|
||||||
|
|
||||||
|
float stepPxs = step * ratio;
|
||||||
|
for (float xPxs = (tick - xMin) * ratio; xPxs <= widthPxs; xPxs += stepPxs, tick += step) {
|
||||||
|
// draw grid line
|
||||||
|
canvas.drawLine(xPxs, 0, xPxs, heightPxs, paint);
|
||||||
|
|
||||||
|
if (Math.abs(tick) >= .001f) {
|
||||||
|
final CharSequence tickLabel = formatTick(tick);
|
||||||
|
|
||||||
|
// draw tick label
|
||||||
|
canvas.drawText(tickLabel, 0, tickLabel.length(), xPxs, y2 + 10, textPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final float x1 = x0 - tickSize;
|
final float x1 = x0px - TICK_SIZE_PXS;
|
||||||
v = ((int) (yMin / step)) * step;
|
tick = ((int) (yMin / step)) * step;
|
||||||
textPaint.setTextAlign(Paint.Align.RIGHT);
|
textPaint.setTextAlign(Paint.Align.RIGHT);
|
||||||
for (float y = height - (v - yMin) * scale; y >= 0; y -= stepScale, v += step) {
|
for (float y = heightPxs - (tick - yMin) * ratio; y >= 0; y -= stepPxs, tick += step) {
|
||||||
canvas.drawLine(0, y, width, y, paint);
|
canvas.drawLine(0, y, widthPxs, y, paint);
|
||||||
if (!(-.001f < v && v < .001f)) {
|
|
||||||
StringBuilder b = format(v);
|
if (Math.abs(tick) >= .001f) {
|
||||||
canvas.drawText(b, 0, b.length(), x1, y + 4, textPaint);
|
final CharSequence tickLabel = formatTick(tick);
|
||||||
|
|
||||||
|
// draw tick label
|
||||||
|
canvas.drawText(tickLabel, 0, tickLabel.length(), x1, y + 4, textPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,17 +518,15 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
// AXIS
|
// AXIS
|
||||||
|
|
||||||
paint.setColor(graphViewHelper.getFunctionViewDef().getAxisColor());
|
paint.setColor(graphViewHelper.getFunctionViewDef().getAxisColor());
|
||||||
if (drawYAxis) {
|
canvas.drawLine(x0px, 0, x0px, heightPxs, paint);
|
||||||
canvas.drawLine(x0, 0, x0, height, paint);
|
canvas.drawLine(0, y0px, widthPxs, y0px, paint);
|
||||||
}
|
|
||||||
canvas.drawLine(0, y0, width, y0, paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
matrix.reset();
|
matrix.reset();
|
||||||
matrix.preTranslate(-this.x0, -this.y0);
|
matrix.preTranslate(-this.x0, -this.y0);
|
||||||
matrix.postScale(scale, -scale);
|
matrix.postScale(ratio, -ratio);
|
||||||
matrix.postTranslate(width / 2, height / 2);
|
matrix.postTranslate(widthPxs / 2, heightPxs / 2);
|
||||||
|
|
||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
|
|
||||||
@ -546,18 +556,78 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
lastXMin = xMin;
|
lastXMin = xMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* BOUNDARIES
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
// X
|
||||||
|
|
||||||
|
public float getXMin() {
|
||||||
|
return x0 - graphWidth / 2;
|
||||||
|
}
|
||||||
|
|
||||||
private float getXMax(float minX) {
|
private float getXMax(float minX) {
|
||||||
return minX + graphWidth;
|
return minX + graphWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getXMax() {
|
public float getXMax() {
|
||||||
return getXMax(getXMin());
|
return getXMax(getXMin());
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getXMin() {
|
// Y
|
||||||
return x0 - graphWidth / 2;
|
|
||||||
|
@Override
|
||||||
|
public float getYMin() {
|
||||||
|
return getYMin(getGraphHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public float getYMin(float graphHeight) {
|
||||||
|
return y0 - graphHeight / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getYMax() {
|
||||||
|
final float graphHeight = getGraphHeight();
|
||||||
|
return getYMax(graphHeight, getYMin(graphHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYMax(float graphHeight, float yMin) {
|
||||||
|
return yMin + graphHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getGraphHeight() {
|
||||||
|
return graphWidth * getAspectRatio();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getRatio() {
|
||||||
|
if (graphWidth != 0) {
|
||||||
|
return widthPxs / graphWidth;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAspectRatio() {
|
||||||
|
if (widthPxs != 0) {
|
||||||
|
return heightPxs / widthPxs;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* ZOOM
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
private boolean canZoomIn() {
|
private boolean canZoomIn() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -566,15 +636,40 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidateGraphs() {
|
public void onVisibilityChanged(boolean visible) {
|
||||||
clearAllGraphs();
|
|
||||||
lastYMin = lastYMax = 0;
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onZoom(boolean zoomIn) {
|
||||||
|
if (zoomIn) {
|
||||||
|
if (canZoomIn()) {
|
||||||
|
graphWidth /= 2;
|
||||||
|
invalidateGraphs();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (canZoomOut()) {
|
||||||
|
graphWidth *= 2;
|
||||||
|
invalidateGraphs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zoomController.setZoomInEnabled(canZoomIn());
|
||||||
|
zoomController.setZoomOutEnabled(canZoomOut());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* TOUCH
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(@NotNull MotionEvent event) {
|
||||||
return touchHandler != null ? touchHandler.onTouchEvent(event) : super.onTouchEvent(event);
|
boolean handled = touchHandler.handleTouchEvent(event);
|
||||||
|
if (!handled) {
|
||||||
|
handled = super.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTouchDown(float x, float y) {
|
public void onTouchDown(float x, float y) {
|
||||||
@ -598,9 +693,11 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onTouchUp(float x, float y) {
|
public void onTouchUp(float x, float y) {
|
||||||
final float scale = width / graphWidth;
|
final float ratio = getRatio();
|
||||||
float sx = -touchHandler.velocityTracker.getXVelocity();
|
|
||||||
float sy = touchHandler.velocityTracker.getYVelocity();
|
float sx = -touchHandler.getXVelocity();
|
||||||
|
float sy = touchHandler.getYVelocity();
|
||||||
|
|
||||||
final float asx = Math.abs(sx);
|
final float asx = Math.abs(sx);
|
||||||
final float asy = Math.abs(sy);
|
final float asy = Math.abs(sy);
|
||||||
if (asx < asy / 3) {
|
if (asx < asy / 3) {
|
||||||
@ -608,9 +705,7 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
} else if (asy < asx / 3) {
|
} else if (asy < asx / 3) {
|
||||||
sy = 0;
|
sy = 0;
|
||||||
}
|
}
|
||||||
scroller.fling(Math.round(x0 * scale),
|
scroller.fling(Math.round(x0 * ratio), Math.round(y0 * ratio), Math.round(sx), Math.round(sy), Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
Math.round(y0 * scale),
|
|
||||||
Math.round(sx), Math.round(sy), -10000, 10000, -10000, 10000);
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,8 +726,14 @@ public class Graph2dViewNew extends View implements GraphView {
|
|||||||
// Calculator.log("zoom redraw");
|
// Calculator.log("zoom redraw");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void invalidateGraphs() {
|
||||||
|
clearAllGraphs();
|
||||||
|
lastYMin = lastYMax = 0;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
private void scroll(float deltaX, float deltaY) {
|
private void scroll(float deltaX, float deltaY) {
|
||||||
final float scale = graphWidth / width;
|
final float scale = graphWidth / widthPxs;
|
||||||
float dx = deltaX * scale;
|
float dx = deltaX * scale;
|
||||||
float dy = deltaY * scale;
|
float dy = deltaY * scale;
|
||||||
final float adx = Math.abs(dx);
|
final float adx = Math.abs(dx);
|
@ -19,7 +19,7 @@ import java.util.List;
|
|||||||
* Date: 12/30/12
|
* Date: 12/30/12
|
||||||
* Time: 4:43 PM
|
* Time: 4:43 PM
|
||||||
*/
|
*/
|
||||||
public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment {
|
public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private GraphView graphView;
|
private GraphView graphView;
|
||||||
@ -28,8 +28,7 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
@Override
|
@Override
|
||||||
protected PlotBoundaries getPlotBoundaries() {
|
protected PlotBoundaries getPlotBoundaries() {
|
||||||
if ( graphView != null ) {
|
if ( graphView != null ) {
|
||||||
// todo serso: return plot boundaries
|
return PlotBoundaries.newInstance(graphView.getXMin(), graphView.getXMax(), graphView.getYMin(), graphView.getYMax());
|
||||||
return null;
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -70,7 +69,7 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
if ( plotData.isPlot3d() ) {
|
if ( plotData.isPlot3d() ) {
|
||||||
graphView = new Graph3dView(getActivity());
|
graphView = new Graph3dView(getActivity());
|
||||||
} else {
|
} else {
|
||||||
graphView = new Graph2dView(getActivity());
|
graphView = new CalculatorGraph2dView(getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
|
graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
|
@ -1,618 +0,0 @@
|
|||||||
// Copyright (C) 2009-2010 Mihai Preda
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator.plot;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.DashPathEffect;
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Path;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
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.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Graph2dView extends View implements GraphView {
|
|
||||||
|
|
||||||
private int width, height;
|
|
||||||
private Matrix matrix = new Matrix();
|
|
||||||
private Paint paint = new Paint(), textPaint = new Paint(), fillPaint = new Paint();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
|
|
||||||
|
|
||||||
private final GraphData next = GraphData.newEmptyInstance();
|
|
||||||
|
|
||||||
private final GraphData endGraph = GraphData.newEmptyInstance();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private List<GraphData> graphs = new ArrayList<GraphData>(graphViewHelper.getFunctionPlotDefs().size());
|
|
||||||
|
|
||||||
private float gwidth = 8;
|
|
||||||
private float currentX, currentY;
|
|
||||||
private float lastMinX;
|
|
||||||
private Scroller scroller;
|
|
||||||
private float boundMinY, boundMaxY;
|
|
||||||
protected ZoomButtonsController zoomController = new ZoomButtonsController(this);
|
|
||||||
private ZoomTracker zoomTracker = new ZoomTracker();
|
|
||||||
private TouchHandler touchHandler;
|
|
||||||
private float lastTouchX, lastTouchY;
|
|
||||||
|
|
||||||
private static final int
|
|
||||||
COL_ZOOM = 0x40ffffff,
|
|
||||||
COL_ZOOM_TEXT1 = 0xd0ffffff,
|
|
||||||
COL_ZOOM_TEXT2 = 0x30ffffff;
|
|
||||||
|
|
||||||
public Graph2dView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
init(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Graph2dView(Context context) {
|
|
||||||
super(context);
|
|
||||||
touchHandler = new TouchHandler(this);
|
|
||||||
init(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(Context context) {
|
|
||||||
zoomController.setOnZoomListener(this);
|
|
||||||
scroller = new Scroller(context);
|
|
||||||
paint.setAntiAlias(false);
|
|
||||||
textPaint.setAntiAlias(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Bitmap captureScreenshot() {
|
|
||||||
final Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
|
||||||
Canvas canvas = new Canvas(result);
|
|
||||||
onDraw(canvas);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setXRange(float xMin, float xMax) {
|
|
||||||
this.gwidth = xMax - xMin;
|
|
||||||
this.currentX = xMax - this.gwidth / 2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearAllGraphs() {
|
|
||||||
for (GraphData graph : graphs) {
|
|
||||||
graph.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( graphViewHelper.getFunctionPlotDefs().size() > graphs.size() ) {
|
|
||||||
graphs.add(GraphData.newEmptyInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
|
||||||
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<ArityPlotFunction>emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<ArityPlotFunction> functionPlotDefs) {
|
|
||||||
|
|
||||||
for (ArityPlotFunction functionPlotDef: functionPlotDefs) {
|
|
||||||
final int arity = functionPlotDef.getFunction().arity();
|
|
||||||
if (arity != 0 && arity != 1) {
|
|
||||||
throw new IllegalArgumentException("Function must have arity 0 or 1 for 2d plot!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs);
|
|
||||||
clearAllGraphs();
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onVisibilityChanged(boolean visible) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onZoom(boolean zoomIn) {
|
|
||||||
if (zoomIn) {
|
|
||||||
if (canZoomIn()) {
|
|
||||||
gwidth /= 2;
|
|
||||||
invalidateGraphs();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (canZoomOut()) {
|
|
||||||
gwidth *= 2;
|
|
||||||
invalidateGraphs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zoomController.setZoomInEnabled(canZoomIn());
|
|
||||||
zoomController.setZoomOutEnabled(canZoomOut());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResume() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPause() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDetachedFromWindow() {
|
|
||||||
zoomController.setVisible(false);
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
|
||||||
width = w;
|
|
||||||
height = h;
|
|
||||||
clearAllGraphs();
|
|
||||||
// points = new float[w+w];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
if (graphViewHelper.getFunctionPlotDefs().size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (scroller.computeScrollOffset()) {
|
|
||||||
final float scale = gwidth / width;
|
|
||||||
currentX = scroller.getCurrX() * scale;
|
|
||||||
currentY = scroller.getCurrY() * scale;
|
|
||||||
if (!scroller.isFinished()) {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drawGraph(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float eval(Function f, float x) {
|
|
||||||
float v = (float) f.eval(x);
|
|
||||||
// Calculator.log("eval " + x + "; " + v);
|
|
||||||
if (v < -10000f) {
|
|
||||||
return -10000f;
|
|
||||||
}
|
|
||||||
if (v > 10000f) {
|
|
||||||
return 10000f;
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
float dx = x2 - x1;
|
|
||||||
float dy = y2 - y1;
|
|
||||||
float mx = x - x1;
|
|
||||||
float my = y - y1;
|
|
||||||
float up = dx*my - dy*mx;
|
|
||||||
return up*up*4/(dx*dx + dy*dy);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// distance as above when x==(x1+x2)/2.
|
|
||||||
private float distance2(float x1, float y1, float x2, float y2, float y) {
|
|
||||||
final float dx = x2 - x1;
|
|
||||||
final float dy = y2 - y1;
|
|
||||||
final float up = dx * (y1 + y2 - y - y);
|
|
||||||
return up * up / (dx * dx + dy * dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void computeGraph(@NotNull Function function,
|
|
||||||
float minX,
|
|
||||||
float maxX,
|
|
||||||
float minY,
|
|
||||||
float maxY,
|
|
||||||
@NotNull GraphData graph) {
|
|
||||||
if (function.arity() == 0) {
|
|
||||||
float v = (float) function.eval();
|
|
||||||
if (v < -10000f) {
|
|
||||||
v = -10000f;
|
|
||||||
}
|
|
||||||
if (v > 10000f) {
|
|
||||||
v = 10000f;
|
|
||||||
}
|
|
||||||
graph.clear();
|
|
||||||
graph.push(minX, v);
|
|
||||||
graph.push(maxX, v);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final float scale = width / gwidth;
|
|
||||||
final float maxStep = 15.8976f / scale;
|
|
||||||
final float minStep = .05f / scale;
|
|
||||||
float ythresh = 1 / scale;
|
|
||||||
ythresh = ythresh * ythresh;
|
|
||||||
// next.clear();
|
|
||||||
// endGraph.clear();
|
|
||||||
if (!graph.empty()) {
|
|
||||||
// Calculator.log("last " + lastMinX + " min " + minX);
|
|
||||||
if (minX >= lastMinX) {
|
|
||||||
graph.eraseBefore(minX);
|
|
||||||
} else {
|
|
||||||
graph.eraseAfter(maxX);
|
|
||||||
maxX = Math.min(maxX, graph.firstX());
|
|
||||||
graph.swap(endGraph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (graph.empty()) {
|
|
||||||
graph.push(minX, eval(function, minX));
|
|
||||||
}
|
|
||||||
float leftX, leftY;
|
|
||||||
float rightX = graph.topX(), rightY = graph.topY();
|
|
||||||
int nEval = 1;
|
|
||||||
while (true) {
|
|
||||||
leftX = rightX;
|
|
||||||
leftY = rightY;
|
|
||||||
if (leftX > maxX) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (next.empty()) {
|
|
||||||
float x = leftX + maxStep;
|
|
||||||
next.push(x, eval(function, x));
|
|
||||||
++nEval;
|
|
||||||
}
|
|
||||||
rightX = next.topX();
|
|
||||||
rightY = next.topY();
|
|
||||||
next.pop();
|
|
||||||
|
|
||||||
if (leftY != leftY && rightY != rightY) { // NaN
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dx = rightX - leftX;
|
|
||||||
float middleX = (leftX + rightX) / 2;
|
|
||||||
float middleY = eval(function, middleX);
|
|
||||||
++nEval;
|
|
||||||
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
|
||||||
if (dx < minStep) {
|
|
||||||
// Calculator.log("minStep");
|
|
||||||
if (middleIsOutside) {
|
|
||||||
graph.push(rightX, Float.NaN);
|
|
||||||
}
|
|
||||||
graph.push(rightX, rightY);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (middleIsOutside && ((leftY < minY && rightY > maxY) || (leftY > maxY && rightY < minY))) {
|
|
||||||
graph.push(rightX, Float.NaN);
|
|
||||||
graph.push(rightX, rightY);
|
|
||||||
// Calculator.log("+-inf");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!middleIsOutside) {
|
|
||||||
/*
|
|
||||||
float diff = leftY + rightY - middleY - middleY;
|
|
||||||
float dy = rightY - leftY;
|
|
||||||
float dx2 = dx*dx;
|
|
||||||
float distance = dx2*diff*diff/(dx2+dy*dy);
|
|
||||||
*/
|
|
||||||
// Calculator.log("" + dx + ' ' + leftY + ' ' + middleY + ' ' + rightY + ' ' + distance + ' ' + ythresh);
|
|
||||||
if (distance2(leftX, leftY, rightX, rightY, middleY) < ythresh) {
|
|
||||||
graph.push(rightX, rightY);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next.push(rightX, rightY);
|
|
||||||
next.push(middleX, middleY);
|
|
||||||
rightX = leftX;
|
|
||||||
rightY = leftY;
|
|
||||||
}
|
|
||||||
if (!endGraph.empty()) {
|
|
||||||
graph.append(endGraph);
|
|
||||||
}
|
|
||||||
long t2 = System.currentTimeMillis();
|
|
||||||
// Calculator.log("graph points " + graph.size + " evals " + nEval + " time " + (t2-t1));
|
|
||||||
|
|
||||||
next.clear();
|
|
||||||
endGraph.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void graphToPath(@NotNull GraphData graph, @NotNull Path path) {
|
|
||||||
|
|
||||||
final int size = graph.getSize();
|
|
||||||
final float[] xs = graph.getXs();
|
|
||||||
final float[] ys = graph.getYs();
|
|
||||||
|
|
||||||
path.rewind();
|
|
||||||
|
|
||||||
boolean newCurve = true;
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
|
|
||||||
final float y = ys[i];
|
|
||||||
final float x = xs[i];
|
|
||||||
|
|
||||||
if (y != y) {
|
|
||||||
newCurve = true;
|
|
||||||
} else { // !NaN
|
|
||||||
if (newCurve) {
|
|
||||||
path.moveTo(x, y);
|
|
||||||
newCurve = false;
|
|
||||||
} else {
|
|
||||||
path.lineTo(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final float NTICKS = 15;
|
|
||||||
|
|
||||||
private static float stepFactor(float w) {
|
|
||||||
float f = 1;
|
|
||||||
while (w / f > NTICKS) {
|
|
||||||
f *= 10;
|
|
||||||
}
|
|
||||||
while (w / f < NTICKS / 10) {
|
|
||||||
f /= 10;
|
|
||||||
}
|
|
||||||
float r = w / f;
|
|
||||||
if (r < NTICKS / 5) {
|
|
||||||
return f / 5;
|
|
||||||
} else if (r < NTICKS / 2) {
|
|
||||||
return f / 2;
|
|
||||||
} else {
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder b = new StringBuilder();
|
|
||||||
private static char[] buf = new char[20];
|
|
||||||
|
|
||||||
private static StringBuilder format(final float value) {
|
|
||||||
int pos = 0;
|
|
||||||
boolean addDot = false;
|
|
||||||
|
|
||||||
final boolean negative = value < 0;
|
|
||||||
|
|
||||||
int absValue = Math.round(Math.abs(value) * 100);
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
int digit = absValue % 10;
|
|
||||||
absValue /= 10;
|
|
||||||
if (digit != 0 || addDot) {
|
|
||||||
buf[pos++] = (char) ('0' + digit);
|
|
||||||
addDot = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addDot) {
|
|
||||||
buf[pos++] = '.';
|
|
||||||
}
|
|
||||||
if (absValue == 0) {
|
|
||||||
buf[pos++] = '0';
|
|
||||||
}
|
|
||||||
while (absValue != 0) {
|
|
||||||
buf[pos++] = (char) ('0' + (absValue % 10));
|
|
||||||
absValue /= 10;
|
|
||||||
}
|
|
||||||
if (negative) {
|
|
||||||
buf[pos++] = '-';
|
|
||||||
}
|
|
||||||
b.setLength(0);
|
|
||||||
b.append(buf, 0, pos);
|
|
||||||
b.reverse();
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawGraph(Canvas canvas) {
|
|
||||||
long t1 = System.currentTimeMillis();
|
|
||||||
float minX = getXMin();
|
|
||||||
float maxX = getXMax(minX);
|
|
||||||
float ywidth = gwidth * height / width;
|
|
||||||
float minY = currentY - ywidth / 2;
|
|
||||||
float maxY = minY + ywidth;
|
|
||||||
if (minY < boundMinY || maxY > boundMaxY) {
|
|
||||||
float halfw = ywidth / 2;
|
|
||||||
boundMinY = minY - halfw;
|
|
||||||
boundMaxY = maxY + halfw;
|
|
||||||
clearAllGraphs();
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.drawColor(graphViewHelper.getFunctionViewDef().getBackgroundColor());
|
|
||||||
|
|
||||||
paint.setStrokeWidth(0);
|
|
||||||
paint.setAntiAlias(false);
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
|
|
||||||
final float h2 = height / 2f;
|
|
||||||
final float scale = width / gwidth;
|
|
||||||
|
|
||||||
float x0 = -minX * scale;
|
|
||||||
boolean drawYAxis = true;
|
|
||||||
if (x0 < 25) {
|
|
||||||
x0 = 25;
|
|
||||||
// drawYAxis = false;
|
|
||||||
} else if (x0 > width - 3) {
|
|
||||||
x0 = width - 3;
|
|
||||||
// drawYAxis = false;
|
|
||||||
}
|
|
||||||
float y0 = maxY * scale;
|
|
||||||
if (y0 < 3) {
|
|
||||||
y0 = 3;
|
|
||||||
} else if (y0 > height - 15) {
|
|
||||||
y0 = height - 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
final float tickSize = 3;
|
|
||||||
final float y2 = y0 + tickSize;
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
// GRID
|
|
||||||
|
|
||||||
paint.setPathEffect(new DashPathEffect(new float[]{5, 10}, 0));
|
|
||||||
paint.setColor(graphViewHelper.getFunctionViewDef().getGridColor());
|
|
||||||
|
|
||||||
float step = stepFactor(gwidth);
|
|
||||||
// Calculator.log("width " + gwidth + " step " + step);
|
|
||||||
float v = ((int) (minX / step)) * step;
|
|
||||||
textPaint.setColor(graphViewHelper.getFunctionViewDef().getAxisLabelsColor());
|
|
||||||
textPaint.setTextSize(12);
|
|
||||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
|
||||||
float stepScale = step * scale;
|
|
||||||
for (float x = (v - minX) * scale; x <= width; x += stepScale, v += step) {
|
|
||||||
canvas.drawLine(x, 0, x, height, paint);
|
|
||||||
if (!(-.001f < v && v < .001f)) {
|
|
||||||
StringBuilder b = format(v);
|
|
||||||
canvas.drawText(b, 0, b.length(), x, y2 + 10, textPaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final float x1 = x0 - tickSize;
|
|
||||||
v = ((int) (minY / step)) * step;
|
|
||||||
textPaint.setTextAlign(Paint.Align.RIGHT);
|
|
||||||
for (float y = height - (v - minY) * scale; y >= 0; y -= stepScale, v += step) {
|
|
||||||
canvas.drawLine(0, y, width, y, paint);
|
|
||||||
if (!(-.001f < v && v < .001f)) {
|
|
||||||
StringBuilder b = format(v);
|
|
||||||
canvas.drawText(b, 0, b.length(), x1, y + 4, textPaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
paint.setPathEffect(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// AXIS
|
|
||||||
|
|
||||||
paint.setColor(graphViewHelper.getFunctionViewDef().getAxisColor());
|
|
||||||
if (drawYAxis) {
|
|
||||||
canvas.drawLine(x0, 0, x0, height, paint);
|
|
||||||
}
|
|
||||||
canvas.drawLine(0, y0, width, y0, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
matrix.reset();
|
|
||||||
matrix.preTranslate(-currentX, -currentY);
|
|
||||||
matrix.postScale(scale, -scale);
|
|
||||||
matrix.postTranslate(width / 2, height / 2);
|
|
||||||
|
|
||||||
paint.setAntiAlias(false);
|
|
||||||
|
|
||||||
{
|
|
||||||
//GRAPH
|
|
||||||
|
|
||||||
final List<ArityPlotFunction> 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(), minX, maxX, boundMinY, boundMaxY, graphs.get(i));
|
|
||||||
|
|
||||||
graphToPath(graphs.get(i), path);
|
|
||||||
|
|
||||||
path.transform(matrix);
|
|
||||||
|
|
||||||
AbstractCalculatorPlotFragment.applyToPaint(fpd.getLineDef(), paint);
|
|
||||||
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lastMinX = minX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getXMax(float minX) {
|
|
||||||
return minX + gwidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getXMax() {
|
|
||||||
return getXMax(getXMin());
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getXMin() {
|
|
||||||
return currentX - gwidth / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canZoomIn() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canZoomOut() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invalidateGraphs() {
|
|
||||||
clearAllGraphs();
|
|
||||||
boundMinY = boundMaxY = 0;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
|
||||||
return touchHandler != null ? touchHandler.onTouchEvent(event) : super.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTouchDown(float x, float y) {
|
|
||||||
zoomController.setVisible(true);
|
|
||||||
if (!scroller.isFinished()) {
|
|
||||||
scroller.abortAnimation();
|
|
||||||
}
|
|
||||||
lastTouchX = x;
|
|
||||||
lastTouchY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTouchMove(float x, float y) {
|
|
||||||
float deltaX = x - lastTouchX;
|
|
||||||
float deltaY = y - lastTouchY;
|
|
||||||
if (deltaX < -1 || deltaX > 1 || deltaY < -1 || deltaY > 1) {
|
|
||||||
scroll(-deltaX, deltaY);
|
|
||||||
lastTouchX = x;
|
|
||||||
lastTouchY = y;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTouchUp(float x, float y) {
|
|
||||||
final float scale = width / gwidth;
|
|
||||||
float sx = -touchHandler.velocityTracker.getXVelocity();
|
|
||||||
float sy = touchHandler.velocityTracker.getYVelocity();
|
|
||||||
final float asx = Math.abs(sx);
|
|
||||||
final float asy = Math.abs(sy);
|
|
||||||
if (asx < asy / 3) {
|
|
||||||
sx = 0;
|
|
||||||
} else if (asy < asx / 3) {
|
|
||||||
sy = 0;
|
|
||||||
}
|
|
||||||
scroller.fling(Math.round(currentX * scale),
|
|
||||||
Math.round(currentY * scale),
|
|
||||||
Math.round(sx), Math.round(sy), -10000, 10000, -10000, 10000);
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTouchZoomDown(float x1, float y1, float x2, float y2) {
|
|
||||||
zoomTracker.start(gwidth, x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTouchZoomMove(float x1, float y1, float x2, float y2) {
|
|
||||||
if (!zoomTracker.update(x1, y1, x2, y2)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float targetGwidth = zoomTracker.value;
|
|
||||||
if (targetGwidth > .25f && targetGwidth < 200) {
|
|
||||||
gwidth = targetGwidth;
|
|
||||||
}
|
|
||||||
// scroll(-zoomTracker.moveX, zoomTracker.moveY);
|
|
||||||
invalidateGraphs();
|
|
||||||
// Calculator.log("zoom redraw");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scroll(float deltaX, float deltaY) {
|
|
||||||
final float scale = gwidth / width;
|
|
||||||
float dx = deltaX * scale;
|
|
||||||
float dy = deltaY * scale;
|
|
||||||
final float adx = Math.abs(dx);
|
|
||||||
final float ady = Math.abs(dy);
|
|
||||||
if (adx < ady / 3) {
|
|
||||||
dx = 0;
|
|
||||||
} else if (ady < adx / 3) {
|
|
||||||
dy = 0;
|
|
||||||
}
|
|
||||||
currentX += dx;
|
|
||||||
currentY += dy;
|
|
||||||
}
|
|
||||||
}
|
|
@ -133,8 +133,8 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onTouchUp(float x, float y) {
|
public void onTouchUp(float x, float y) {
|
||||||
float vx = touchHandler.velocityTracker.getXVelocity();
|
float vx = touchHandler.getXVelocity();
|
||||||
float vy = touchHandler.velocityTracker.getYVelocity();
|
float vy = touchHandler.getYVelocity();
|
||||||
// Calculator.log("velocity " + vx + ' ' + vy);
|
// Calculator.log("velocity " + vx + ' ' + vy);
|
||||||
setRotation(vx / 100, vy / 100);
|
setRotation(vx / 100, vy / 100);
|
||||||
if (shouldRotate()) {
|
if (shouldRotate()) {
|
||||||
@ -152,7 +152,7 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
return touchHandler != null ? touchHandler.onTouchEvent(event) : super.onTouchEvent(event);
|
return touchHandler != null ? touchHandler.handleTouchEvent(event) : super.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
@ -195,7 +195,27 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
//To change body of implemented methods use File | Settings | File Templates.
|
//To change body of implemented methods use File | Settings | File Templates.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public float getXMin() {
|
||||||
|
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getXMax() {
|
||||||
|
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getYMin() {
|
||||||
|
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getYMax() {
|
||||||
|
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onSurfaceCreated(GL10 gl, int width, int height) {
|
public void onSurfaceCreated(GL10 gl, int width, int height) {
|
||||||
gl.glDisable(GL10.GL_DITHER);
|
gl.glDisable(GL10.GL_DITHER);
|
||||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||||
|
@ -8,9 +8,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHandler.TouchHandlerInterface {
|
public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHandler.TouchHandlerListener {
|
||||||
|
|
||||||
static final String SCREENSHOT_DIR = "/screenshots";
|
|
||||||
|
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef);
|
public void init(@NotNull FunctionViewDef functionViewDef);
|
||||||
|
|
||||||
@ -24,6 +22,14 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa
|
|||||||
|
|
||||||
void setXRange(float xMin, float xMax);
|
void setXRange(float xMin, float xMax);
|
||||||
|
|
||||||
|
float getXMin();
|
||||||
|
|
||||||
|
float getXMax();
|
||||||
|
|
||||||
|
float getYMin();
|
||||||
|
|
||||||
|
float getYMax();
|
||||||
|
|
||||||
/* void increaseDensity();
|
/* void increaseDensity();
|
||||||
void decreaseDensity();*/
|
void decreaseDensity();*/
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// Copyright (C) 2010 Mihai Preda
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator.plot;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
class MotionEventWrap {
|
|
||||||
private static final boolean IS_API_5 = Build.VERSION.SDK_INT >= 5;
|
|
||||||
|
|
||||||
static int getPointerCount(MotionEvent event) {
|
|
||||||
return IS_API_5 ? MotionEventWrapNew.getPointerCount(event) : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getX(MotionEvent event, int idx) {
|
|
||||||
return IS_API_5 ? MotionEventWrapNew.getX(event, idx) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getY(MotionEvent event, int idx) {
|
|
||||||
return IS_API_5 ? MotionEventWrapNew.getX(event, idx) : 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright (C) 2010 Mihai Preda
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator.plot;
|
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
class MotionEventWrapNew {
|
|
||||||
static int getPointerCount(MotionEvent event) {
|
|
||||||
return event.getPointerCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getX(MotionEvent event, int idx) {
|
|
||||||
return event.getX(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getY(MotionEvent event, int idx) {
|
|
||||||
return event.getY(idx);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,76 +4,95 @@ package org.solovyev.android.calculator.plot;
|
|||||||
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.AndroidUtils2;
|
||||||
|
|
||||||
class TouchHandler {
|
class TouchHandler {
|
||||||
static interface TouchHandlerInterface {
|
|
||||||
|
static interface TouchHandlerListener {
|
||||||
void onTouchDown(float x, float y);
|
void onTouchDown(float x, float y);
|
||||||
|
|
||||||
void onTouchMove(float x, float y);
|
void onTouchMove(float x, float y);
|
||||||
void onTouchUp(float x, float y);
|
|
||||||
|
void onTouchUp(float x, float y);
|
||||||
|
|
||||||
void onTouchZoomDown(float x1, float y1, float x2, float y2);
|
void onTouchZoomDown(float x1, float y1, float x2, float y2);
|
||||||
|
|
||||||
void onTouchZoomMove(float x1, float y1, float x2, float y2);
|
void onTouchZoomMove(float x1, float y1, float x2, float y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
VelocityTracker velocityTracker = VelocityTracker.obtain();
|
@NotNull
|
||||||
|
private final VelocityTracker velocityTracker = VelocityTracker.obtain();
|
||||||
|
|
||||||
private boolean isAfterZoom;
|
private boolean afterZoom;
|
||||||
private TouchHandlerInterface listener;
|
|
||||||
|
|
||||||
TouchHandler(TouchHandlerInterface listener) {
|
@NotNull
|
||||||
|
private TouchHandlerListener listener;
|
||||||
|
|
||||||
|
TouchHandler(@NotNull TouchHandlerListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean handleTouchEvent(@NotNull MotionEvent event) {
|
||||||
// Calculator.log("touch " + event + ' ' + event.getPointerCount() + event.getPointerId(0));
|
// Calculator.log("touch " + event + ' ' + event.getPointerCount() + event.getPointerId(0));
|
||||||
|
|
||||||
int fullAction = event.getAction();
|
final int fullAction = event.getAction();
|
||||||
int action = fullAction & MotionEvent.ACTION_MASK;
|
final int action = fullAction & MotionEvent.ACTION_MASK;
|
||||||
int pointer = (fullAction & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
|
final int pointer = (fullAction & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
|
||||||
|
|
||||||
float x = event.getX();
|
float x = event.getX();
|
||||||
float y = event.getY();
|
float y = event.getY();
|
||||||
int nPoints = MotionEventWrap.getPointerCount(event);
|
|
||||||
|
int pointerCount = AndroidUtils2.getPointerCountFromMotionEvent(event);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
isAfterZoom = false;
|
afterZoom = false;
|
||||||
velocityTracker.clear();
|
velocityTracker.clear();
|
||||||
velocityTracker.addMovement(event);
|
|
||||||
listener.onTouchDown(x, y);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
if (nPoints == 1) {
|
|
||||||
if (isAfterZoom) {
|
|
||||||
velocityTracker.clear();
|
|
||||||
listener.onTouchDown(x, y);
|
|
||||||
isAfterZoom = false;
|
|
||||||
}
|
|
||||||
velocityTracker.addMovement(event);
|
velocityTracker.addMovement(event);
|
||||||
listener.onTouchMove(x, y);
|
listener.onTouchDown(x, y);
|
||||||
} else if (nPoints == 2) {
|
break;
|
||||||
listener.onTouchZoomMove(x, y, MotionEventWrap.getX(event, 1), MotionEventWrap.getY(event, 1));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_MOVE:
|
||||||
velocityTracker.addMovement(event);
|
if (pointerCount == 1) {
|
||||||
velocityTracker.computeCurrentVelocity(1000);
|
if (afterZoom) {
|
||||||
listener.onTouchUp(x, y);
|
velocityTracker.clear();
|
||||||
break;
|
listener.onTouchDown(x, y);
|
||||||
|
afterZoom = false;
|
||||||
|
}
|
||||||
|
velocityTracker.addMovement(event);
|
||||||
|
listener.onTouchMove(x, y);
|
||||||
|
} else if (pointerCount == 2) {
|
||||||
|
listener.onTouchZoomMove(x, y, AndroidUtils2.getXFromMotionEvent(event, 1), AndroidUtils2.getYFromMotionEvent(event, 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_POINTER_DOWN:
|
case MotionEvent.ACTION_UP:
|
||||||
if (nPoints == 2) {
|
velocityTracker.addMovement(event);
|
||||||
listener.onTouchZoomDown(x, y, MotionEventWrap.getX(event, 1), MotionEventWrap.getY(event, 1));
|
velocityTracker.computeCurrentVelocity(1000);
|
||||||
}
|
listener.onTouchUp(x, y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_POINTER_UP:
|
case MotionEvent.ACTION_POINTER_DOWN:
|
||||||
if (nPoints == 2) {
|
if (pointerCount == 2) {
|
||||||
isAfterZoom = true;
|
listener.onTouchZoomDown(x, y, AndroidUtils2.getXFromMotionEvent(event, 1), AndroidUtils2.getYFromMotionEvent(event, 1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
if (pointerCount == 2) {
|
||||||
|
afterZoom = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getXVelocity() {
|
||||||
|
return velocityTracker.getXVelocity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYVelocity() {
|
||||||
|
return velocityTracker.getYVelocity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user