new plotter
This commit is contained in:
parent
5f7ee1e64e
commit
2c0803da74
@ -5,8 +5,16 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 03.10.12
|
||||
@ -55,4 +63,43 @@ public final class AndroidUtils2 {
|
||||
int componentEnabledSetting = pm.getComponentEnabledSetting(new ComponentName(context, componentClass));
|
||||
return componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
public static String saveBitmap(@NotNull Bitmap bitmap,
|
||||
@NotNull String path,
|
||||
@NotNull String fileName) {
|
||||
final File sdcardPath = Environment.getExternalStorageDirectory();
|
||||
final File filePath = new File(sdcardPath, path);
|
||||
|
||||
filePath.mkdirs();
|
||||
|
||||
final String fullFileName = fileName + "_" + System.currentTimeMillis() + ".png";
|
||||
|
||||
final File file = new File(path, fullFileName);
|
||||
if (!file.exists()) {
|
||||
final String name = file.getAbsolutePath();
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(name);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.flush();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e("AndroidUtils", e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
Log.e("AndroidUtils", e.getMessage(), e);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("AndroidUtils", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
package arity.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
@ -18,8 +17,9 @@ import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import org.javia.arity.*;
|
||||
import org.javia.arity.Util;
|
||||
import org.solovyev.android.calculator.Locator;
|
||||
import org.solovyev.android.calculator.plot.Graph2dView;
|
||||
import org.solovyev.android.calculator.plot.Graph3dView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -183,9 +183,6 @@ public class Calculator extends Activity implements TextWatcher,
|
||||
|
||||
//OnClickListener
|
||||
public void onClick(View target) {
|
||||
if (target == graphView || target == graph3dView) {
|
||||
startActivity(new Intent(this, ShowGraph.class));
|
||||
}
|
||||
}
|
||||
|
||||
// OnItemClickListener
|
||||
@ -323,7 +320,7 @@ public class Calculator extends Activity implements TextWatcher,
|
||||
showGraph(null);
|
||||
}
|
||||
} else {
|
||||
graphView.setFunctions(auxFuncs);
|
||||
//graphView.setFunctionPlotDefs(auxFuncs);
|
||||
if (graphView.getVisibility() != View.VISIBLE) {
|
||||
if (isAlphaVisible) {
|
||||
isAlphaVisible = false;
|
||||
@ -376,7 +373,7 @@ public class Calculator extends Activity implements TextWatcher,
|
||||
} else {
|
||||
// graphedFunction = f;
|
||||
if (f.arity() == 1) {
|
||||
graphView.setFunction(f);
|
||||
//graphView.setFunctionPlotDefs(Arrays.asList(f));
|
||||
if (graphView.getVisibility() != View.VISIBLE) {
|
||||
if (isAlphaVisible) {
|
||||
isAlphaVisible = false;
|
||||
@ -389,7 +386,7 @@ public class Calculator extends Activity implements TextWatcher,
|
||||
graphView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
graph3dView.setFunction(f);
|
||||
//graph3dView.setFunctionPlotDefs(Arrays.asList(f));
|
||||
if (graph3dView.getVisibility() != View.VISIBLE) {
|
||||
if (isAlphaVisible) {
|
||||
isAlphaVisible = false;
|
||||
|
@ -1,85 +0,0 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
class CalculatorEditable extends SpannableStringBuilder {
|
||||
static class Factory extends Editable.Factory {
|
||||
public Editable newEditable(CharSequence source) {
|
||||
return new CalculatorEditable(source);
|
||||
}
|
||||
}
|
||||
|
||||
static final char MINUS = '\u2212', TIMES = '\u00d7', DIV = '\u00f7';
|
||||
private boolean isRec;
|
||||
|
||||
public CalculatorEditable(CharSequence source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public SpannableStringBuilder replace(int start, int end, CharSequence buf, int bufStart, int bufEnd) {
|
||||
if (isRec || bufEnd - bufStart != 1) {
|
||||
return super.replace(start, end, buf, bufStart, bufEnd);
|
||||
} else {
|
||||
isRec = true;
|
||||
try {
|
||||
char c = buf.charAt(bufStart);
|
||||
return internalReplace(start, end, c);
|
||||
} finally {
|
||||
isRec = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
return "\u2212\u00d7\u00f7+-/*=^,".indexOf(c) != -1;
|
||||
}
|
||||
|
||||
private SpannableStringBuilder internalReplace(int start, int end, char c) {
|
||||
switch (c) {
|
||||
case '-': c = MINUS; break;
|
||||
case '*': c = TIMES; break;
|
||||
case '/': c = DIV; break;
|
||||
}
|
||||
if (c == '.') {
|
||||
int p = start - 1;
|
||||
while (p >= 0 && Character.isDigit(charAt(p))) {
|
||||
--p;
|
||||
}
|
||||
if (p >= 0 && charAt(p) == '.') {
|
||||
return super.replace(start, end, "");
|
||||
}
|
||||
}
|
||||
|
||||
char prevChar = start > 0 ? charAt(start-1) : '\0';
|
||||
|
||||
if (c == MINUS && prevChar == MINUS) {
|
||||
return super.replace(start, end, "");
|
||||
}
|
||||
|
||||
if (isOperator(c)) {
|
||||
while (isOperator(prevChar) &&
|
||||
(c != MINUS || prevChar == '+')) {
|
||||
--start;
|
||||
prevChar = start > 0 ? charAt(start-1) : '\0';
|
||||
}
|
||||
}
|
||||
|
||||
//don't allow leading operator + * /
|
||||
if (start == 0 && isOperator(c)) { // && c != MINUS
|
||||
return super.replace(start, end, "ans" + c);
|
||||
}
|
||||
|
||||
//allow at most one '='
|
||||
if (c == '=') {
|
||||
for (int pos = 0; pos < start; ++pos) {
|
||||
if (charAt(pos) == '=') {
|
||||
return super.replace(start, end, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.replace(start, end, "" + c);
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
|
||||
class Data {
|
||||
float[] xs = new float[4];
|
||||
float[] ys = new float[4];
|
||||
int size = 0;
|
||||
int allocSize = 4;
|
||||
|
||||
void swap(Data o) {
|
||||
float savex[] = o.xs;
|
||||
float savey[] = o.ys;
|
||||
int ssize = o.size;
|
||||
int salloc = o.allocSize;
|
||||
|
||||
o.xs = xs;
|
||||
o.ys = ys;
|
||||
o.size = size;
|
||||
o.allocSize = allocSize;
|
||||
|
||||
xs = savex;
|
||||
ys = savey;
|
||||
size = ssize;
|
||||
allocSize = salloc;
|
||||
}
|
||||
|
||||
void push(float x, float y) {
|
||||
if (size >= allocSize) {
|
||||
makeSpace(size+1);
|
||||
}
|
||||
// Calculator.log("push " + size + ' ' + x + ' ' + y);
|
||||
xs[size] = x;
|
||||
ys[size] = y;
|
||||
++size;
|
||||
}
|
||||
|
||||
private void makeSpace(int sizeNeeded) {
|
||||
int oldAllocSize = allocSize;
|
||||
while (sizeNeeded > allocSize) {
|
||||
allocSize += allocSize;
|
||||
}
|
||||
if (oldAllocSize != allocSize) {
|
||||
float[] a = new float[allocSize];
|
||||
System.arraycopy(xs, 0, a, 0, size);
|
||||
xs = a;
|
||||
a = new float[allocSize];
|
||||
System.arraycopy(ys, 0, a, 0, size);
|
||||
ys = a;
|
||||
}
|
||||
}
|
||||
|
||||
float topX() {
|
||||
return xs[size-1];
|
||||
}
|
||||
|
||||
float topY() {
|
||||
return ys[size-1];
|
||||
}
|
||||
|
||||
float firstX() {
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
float firstY() {
|
||||
return ys[0];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
--size;
|
||||
}
|
||||
|
||||
boolean empty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void eraseBefore(float x) {
|
||||
int pos = 0;
|
||||
while (pos < size && xs[pos] < x) {
|
||||
++pos;
|
||||
}
|
||||
--pos;
|
||||
if (pos > 0) {
|
||||
size -= pos;
|
||||
System.arraycopy(xs, pos, xs, 0, size);
|
||||
System.arraycopy(ys, pos, ys, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
void eraseAfter(float x) {
|
||||
int pos = size-1;
|
||||
while (pos >= 0 && x < xs[pos]) {
|
||||
--pos;
|
||||
}
|
||||
++pos;
|
||||
if (pos < size-1) {
|
||||
size = pos+1;
|
||||
}
|
||||
}
|
||||
|
||||
int findPosAfter(float x, float y) {
|
||||
int pos = 0;
|
||||
while (pos < size && xs[pos] <= x) {
|
||||
++pos;
|
||||
}
|
||||
if (Float.isNaN(y)) {
|
||||
while (pos < size && ys[pos] != ys[pos]) {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
// Calculator.log("pos " + pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
void append(Data d) {
|
||||
makeSpace(size + d.size);
|
||||
int pos = d.findPosAfter(xs[size-1], ys[size-1]);
|
||||
/*
|
||||
while (pos < d.size && d.xs[pos] <= last) {
|
||||
++pos;
|
||||
}
|
||||
if (last != last) {
|
||||
while (pos < d.size && d.ys[pos] != d.ys[pos]) {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
*/
|
||||
System.arraycopy(d.xs, pos, xs, size, d.size-pos);
|
||||
System.arraycopy(d.ys, pos, ys, size, d.size-pos);
|
||||
size += d.size-pos;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(size).append(": ");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
b.append(xs[i]).append(", ");
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.WebView;
|
||||
|
||||
public class Help extends Activity {
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
WebView view = new WebView(this);
|
||||
setContentView(view);
|
||||
view.loadUrl("file:///android_asset/help.html");
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import org.javia.arity.Function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ShowGraph extends Activity {
|
||||
|
||||
private GraphView view;
|
||||
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
ArrayList<Function> funcs = Calculator.graphedFunction;
|
||||
if (funcs == null) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
int size = funcs.size();
|
||||
if (size == 1) {
|
||||
Function f = funcs.get(0);
|
||||
view = f.arity() == 1 ? new Graph2dView(this) : new Graph3dView(this);
|
||||
view.setFunction(f);
|
||||
} else {
|
||||
view = new Graph2dView(this);
|
||||
((Graph2dView) view).setFunctions(funcs);
|
||||
}
|
||||
setContentView((View) view);
|
||||
}
|
||||
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
view.onPause();
|
||||
}
|
||||
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
view.onResume();
|
||||
}
|
||||
|
||||
/* public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
(new MenuInflater(this)).inflate(R.menu.graph, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.capture_screenshot:
|
||||
String fileName = view.captureScreenshot();
|
||||
if (fileName != null) {
|
||||
Toast.makeText(this, "screenshot saved as \n" + fileName, Toast.LENGTH_LONG).show();
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setDataAndType(Uri.fromFile(new File(fileName)), "image/png");
|
||||
startActivity(i);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
// Copyright (C) 2009-2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Environment;
|
||||
import android.os.Build;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
import java.io.*;
|
||||
|
||||
class Util {
|
||||
public static final int SDK_VERSION = getSdkVersion();
|
||||
|
||||
private static int getSdkVersion() {
|
||||
try {
|
||||
return Integer.parseInt(Build.VERSION.SDK);
|
||||
} catch (NumberFormatException e) {
|
||||
Calculator.log("invalid SDK " + Build.VERSION.SDK);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
static String saveBitmap(Bitmap bitmap, String dir, String baseName) {
|
||||
try {
|
||||
File sdcard = Environment.getExternalStorageDirectory();
|
||||
File pictureDir = new File(sdcard, dir);
|
||||
pictureDir.mkdirs();
|
||||
File f = null;
|
||||
for (int i = 1; i < 200; ++i) {
|
||||
String name = baseName + i + ".png";
|
||||
f = new File(pictureDir, name);
|
||||
if (!f.exists()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!f.exists()) {
|
||||
String name = f.getAbsolutePath();
|
||||
FileOutputStream fos = new FileOutputStream(name);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
return name;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Calculator.log("exception saving screenshot: " + e);
|
||||
} finally {
|
||||
/*
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
*/
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void bitmapBGRtoRGB(Bitmap bitmap, int width, int height) {
|
||||
int size = width * height;
|
||||
short data[] = new short[size];
|
||||
ShortBuffer buf = ShortBuffer.wrap(data);
|
||||
bitmap.copyPixelsToBuffer(buf);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
//BGR-565 to RGB-565
|
||||
short v = data[i];
|
||||
data[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
|
||||
}
|
||||
buf.rewind();
|
||||
bitmap.copyPixelsFromBuffer(buf);
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import arity.calculator.Graph2dView;
|
||||
import arity.calculator.Graph3dView;
|
||||
import arity.calculator.GraphView;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.function.Constant;
|
||||
import org.javia.arity.Complex;
|
||||
import org.javia.arity.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorPreferences;
|
||||
import org.solovyev.android.calculator.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -39,6 +39,12 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
||||
|
||||
@Override
|
||||
protected void createGraphicalView(@NotNull View root, @NotNull PreparedInput preparedInput) {
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
|
||||
|
||||
final GraphLineColor realLineColor = CalculatorPreferences.Graph.lineColorReal.getPreference(preferences);
|
||||
final GraphLineColor imagLineColor = CalculatorPreferences.Graph.lineColorImag.getPreference(preferences);
|
||||
|
||||
// remove old
|
||||
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
|
||||
|
||||
@ -53,45 +59,28 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
||||
|
||||
final int arity = yVariable == null ? 1 : 2;
|
||||
|
||||
final List<Function> functions = new ArrayList<Function>();
|
||||
functions.add(new Function() {
|
||||
@Override
|
||||
public int arity() {
|
||||
return arity;
|
||||
}
|
||||
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
||||
|
||||
@Override
|
||||
public double eval(double x) {
|
||||
return PlotUtils.calculatorExpression(expression, xVariable, x).realPart();
|
||||
}
|
||||
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||
|
||||
@Override
|
||||
public double eval(double x, double y) {
|
||||
return PlotUtils.calculatorExpression(expression, xVariable, x, yVariable, y).realPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Complex eval(Complex x) {
|
||||
jscl.math.numeric.Complex result = PlotUtils.calculatorExpression(expression, xVariable, x.re);
|
||||
return new Complex(result.realPart(), result.imaginaryPart());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Complex eval(Complex x, Complex y) {
|
||||
jscl.math.numeric.Complex result = PlotUtils.calculatorExpression(expression, xVariable, x.re, yVariable, y.re);
|
||||
return new Complex(result.realPart(), result.imaginaryPart());
|
||||
}
|
||||
});
|
||||
|
||||
if (functions.size() == 1) {
|
||||
final Function f = functions.get(0);
|
||||
graphView = f.arity() == 1 ? new Graph2dView(getActivity()) : new Graph3dView(getActivity());
|
||||
graphView.setFunction(f);
|
||||
} else {
|
||||
graphView = new Graph2dView(this.getActivity());
|
||||
((Graph2dView) graphView).setFunctions(functions);
|
||||
if (arity == 1) {
|
||||
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||
}
|
||||
|
||||
switch (arity) {
|
||||
case 1:
|
||||
graphView = new Graph2dView(getActivity());
|
||||
break;
|
||||
case 2:
|
||||
graphView = new Graph3dView(getActivity());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported arity: " + arity);
|
||||
}
|
||||
|
||||
graphView.init(FunctionViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
|
||||
graphView.setFunctionPlotDefs(functions);
|
||||
|
||||
graphContainer.addView((View) graphView);
|
||||
} else {
|
||||
onError();
|
||||
@ -128,4 +117,79 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
||||
this.graphView.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* STATIC
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private static abstract class AbstractArityFunction extends Function {
|
||||
|
||||
protected final int arity;
|
||||
|
||||
@NotNull
|
||||
protected final Generic expression;
|
||||
|
||||
@NotNull
|
||||
protected final Constant xVariable;
|
||||
|
||||
@Nullable
|
||||
protected final Constant yVariable;
|
||||
|
||||
public AbstractArityFunction(int arity, @NotNull Generic expression, @NotNull Constant xVariable, @Nullable Constant yVariable) {
|
||||
this.arity = arity;
|
||||
this.expression = expression;
|
||||
this.xVariable = xVariable;
|
||||
this.yVariable = yVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int arity() {
|
||||
return arity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RealArityFunction extends AbstractArityFunction {
|
||||
|
||||
private RealArityFunction(int arity,
|
||||
@NotNull Generic expression,
|
||||
@NotNull Constant xVariable,
|
||||
@Nullable Constant yVariable) {
|
||||
super(arity, expression, xVariable, yVariable);
|
||||
}
|
||||
|
||||
@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,
|
||||
@NotNull Constant xVariable,
|
||||
@Nullable Constant yVariable) {
|
||||
super(arity, expression, xVariable, yVariable);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
class FPS {
|
||||
private int drawCnt;
|
@ -0,0 +1,91 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/5/13
|
||||
* Time: 7:41 PM
|
||||
*/
|
||||
public class FunctionLineDef {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@NotNull
|
||||
private static final Float DEFAULT_LINE_WIDTH = -1f;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private int lineColor = Color.WHITE;
|
||||
|
||||
@NotNull
|
||||
private FunctionLineStyle lineStyle = FunctionLineStyle.solid;
|
||||
|
||||
private float lineWidth = -DEFAULT_LINE_WIDTH;
|
||||
|
||||
private FunctionLineDef() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionLineDef newInstance(int lineColor, @NotNull FunctionLineStyle lineStyle) {
|
||||
final FunctionLineDef result = new FunctionLineDef();
|
||||
result.lineColor = lineColor;
|
||||
result.lineStyle = lineStyle;
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionLineDef newInstance(int lineColor, @NotNull FunctionLineStyle lineStyle, float lineWidth) {
|
||||
final FunctionLineDef result = new FunctionLineDef();
|
||||
result.lineColor = lineColor;
|
||||
result.lineStyle = lineStyle;
|
||||
result.lineWidth = lineWidth;
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionLineDef newDefaultInstance() {
|
||||
return new FunctionLineDef();
|
||||
}
|
||||
|
||||
|
||||
public int getLineColor() {
|
||||
return lineColor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionLineStyle getLineStyle() {
|
||||
return lineStyle;
|
||||
}
|
||||
|
||||
public float getLineWidth() {
|
||||
return lineWidth;
|
||||
}
|
||||
|
||||
public void applyToPaint(@NotNull Paint paint) {
|
||||
paint.setColor(lineColor);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
if ( lineWidth == DEFAULT_LINE_WIDTH ) {
|
||||
paint.setStrokeWidth(0);
|
||||
} else {
|
||||
paint.setStrokeWidth(lineWidth);
|
||||
}
|
||||
|
||||
lineStyle.applyToPaint(paint);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/5/13
|
||||
* Time: 7:37 PM
|
||||
*/
|
||||
public enum FunctionLineStyle {
|
||||
|
||||
solid {
|
||||
@Override
|
||||
public void applyToPaint(@NotNull Paint paint) {
|
||||
paint.setPathEffect(null);
|
||||
}
|
||||
},
|
||||
|
||||
dashed {
|
||||
@Override
|
||||
public void applyToPaint(@NotNull Paint paint) {
|
||||
paint.setPathEffect(new DashPathEffect(new float[] {10, 20}, 0));
|
||||
}
|
||||
},
|
||||
|
||||
dotted {
|
||||
@Override
|
||||
public void applyToPaint(@NotNull Paint paint) {
|
||||
paint.setPathEffect(new DashPathEffect(new float[] {5, 1}, 0));
|
||||
}
|
||||
},
|
||||
|
||||
dash_dotted {
|
||||
@Override
|
||||
public void applyToPaint(@NotNull Paint paint) {
|
||||
paint.setPathEffect(new DashPathEffect(new float[] {10, 20, 5, 1}, 0));
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void applyToPaint(@NotNull Paint paint);
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import org.javia.arity.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/5/13
|
||||
* Time: 7:35 PM
|
||||
*/
|
||||
public class FunctionPlotDef {
|
||||
|
||||
@NotNull
|
||||
private Function function;
|
||||
|
||||
@NotNull
|
||||
private FunctionLineDef lineDef;
|
||||
|
||||
private FunctionPlotDef() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionPlotDef newInstance(@NotNull Function function) {
|
||||
return newInstance(function, FunctionLineDef.newDefaultInstance());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionPlotDef newInstance(@NotNull Function function, @NotNull FunctionLineDef lineDef) {
|
||||
final FunctionPlotDef result = new FunctionPlotDef();
|
||||
|
||||
result.function = function;
|
||||
result.lineDef = lineDef;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Function getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionLineDef getLineDef() {
|
||||
return lineDef;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.graphics.Color;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/5/13
|
||||
* Time: 9:11 PM
|
||||
*/
|
||||
public class FunctionViewDef {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private static final int DEFAULT_AXIS_COLOR = 0xff00a000;
|
||||
private static final int DEFAULT_GRID_COLOR = 0xff004000;
|
||||
private static final int DEFAULT_BACKGROUND_COLOR = Color.BLACK;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private int axisColor = DEFAULT_AXIS_COLOR;
|
||||
|
||||
private int axisLabelsColor = DEFAULT_AXIS_COLOR;
|
||||
|
||||
private int gridColor = DEFAULT_GRID_COLOR;
|
||||
|
||||
private int backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
private FunctionViewDef() {
|
||||
}
|
||||
|
||||
private FunctionViewDef(int axisColor, int axisLabelColor, int gridColor, int backgroundColor) {
|
||||
this.axisColor = axisColor;
|
||||
this.axisLabelsColor = axisLabelColor;
|
||||
this.gridColor = gridColor;
|
||||
this.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionViewDef newDefaultInstance() {
|
||||
return new FunctionViewDef();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionViewDef newInstance(int axisColor, int axisLabelColor, int gridColor, int backgroundColor) {
|
||||
return new FunctionViewDef(axisColor, axisLabelColor, gridColor, backgroundColor);
|
||||
}
|
||||
|
||||
public int getAxisColor() {
|
||||
return axisColor;
|
||||
}
|
||||
|
||||
public int getAxisLabelsColor() {
|
||||
return axisLabelsColor;
|
||||
}
|
||||
|
||||
public int getGridColor() {
|
||||
return gridColor;
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
@ -9,12 +9,14 @@ import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import org.solovyev.android.AndroidUtils2;
|
||||
|
||||
import javax.microedition.khronos.egl.*;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import javax.microedition.khronos.opengles.GL11;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
private boolean hasSurface;
|
||||
@ -33,8 +35,8 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
|
||||
public String captureScreenshot() {
|
||||
Bitmap bitmap = getRawPixels(gl, width, height);
|
||||
Util.bitmapBGRtoRGB(bitmap, width, height);
|
||||
return Util.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||
bitmapBGRtoRGB(bitmap, width, height);
|
||||
return AndroidUtils2.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||
}
|
||||
|
||||
private static Bitmap getRawPixels(GL10 gl, int width, int height) {
|
||||
@ -73,7 +75,6 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
Calculator.log("onResume " + this);
|
||||
paused = false;
|
||||
if (hasSurface) {
|
||||
initGL();
|
||||
@ -81,7 +82,6 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
Calculator.log("onPause " + this);
|
||||
deinitGL();
|
||||
}
|
||||
|
||||
@ -125,10 +125,8 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
if (hasSurface && !paused) {
|
||||
onDrawFrame(gl);
|
||||
if (!egl.eglSwapBuffers(display, surface)) {
|
||||
Calculator.log("swapBuffers error " + egl.eglGetError());
|
||||
}
|
||||
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
|
||||
Calculator.log("egl context lost " + this);
|
||||
paused = true;
|
||||
}
|
||||
if (mIsLooping) {
|
||||
@ -138,11 +136,9 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Calculator.log("surfaceCreated " + this);
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
Calculator.log("surfaceChanged " + format + ' ' + this);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
boolean doInit = !hasSurface && !paused;
|
||||
@ -153,14 +149,12 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Calculator.log("surfaceDestroyed " + this);
|
||||
hasSurface = false;
|
||||
deinitGL();
|
||||
}
|
||||
|
||||
public void startLooping() {
|
||||
if (!mIsLooping) {
|
||||
Calculator.log("start looping");
|
||||
mIsLooping = true;
|
||||
glDraw();
|
||||
}
|
||||
@ -168,7 +162,6 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
|
||||
public void stopLooping() {
|
||||
if (mIsLooping) {
|
||||
Calculator.log("stop looping");
|
||||
mIsLooping = false;
|
||||
}
|
||||
}
|
||||
@ -180,4 +173,18 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
public void requestDraw() {
|
||||
handler.sendEmptyMessage(1);
|
||||
}
|
||||
|
||||
static void bitmapBGRtoRGB(Bitmap bitmap, int width, int height) {
|
||||
int size = width * height;
|
||||
short data[] = new short[size];
|
||||
ShortBuffer buf = ShortBuffer.wrap(data);
|
||||
bitmap.copyPixelsToBuffer(buf);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
//BGR-565 to RGB-565
|
||||
short v = data[i];
|
||||
data[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
|
||||
}
|
||||
buf.rewind();
|
||||
bitmap.copyPixelsFromBuffer(buf);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2009-2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.*;
|
||||
@ -10,22 +11,29 @@ import android.view.View;
|
||||
import android.widget.Scroller;
|
||||
import android.widget.ZoomButtonsController;
|
||||
import org.javia.arity.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.AndroidUtils2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Graph2dView extends View implements
|
||||
GraphView,
|
||||
ZoomButtonsController.OnZoomListener,
|
||||
TouchHandler.TouchHandlerInterface {
|
||||
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();
|
||||
private ArrayList<Function> funcs = new ArrayList<Function>();
|
||||
private Data next = new Data(), endGraph = new Data();
|
||||
private Data graphs[] = {new Data(), new Data(), new Data(), new Data(), new Data()};
|
||||
private static final int GRAPHS_SIZE = 5;
|
||||
|
||||
@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;
|
||||
@ -36,13 +44,6 @@ public class Graph2dView extends View implements
|
||||
private TouchHandler touchHandler;
|
||||
private float lastTouchX, lastTouchY;
|
||||
|
||||
private static final int
|
||||
COL_AXIS = 0xff00a000,
|
||||
COL_GRID = 0xff004000,
|
||||
COL_TEXT = 0xff00ff00;
|
||||
|
||||
private static final int COL_GRAPH[] = {0xffffffff, 0xff00ffff, 0xffffff00, 0xffff00ff, 0xff80ff80};
|
||||
|
||||
private static final int
|
||||
COL_ZOOM = 0x40ffffff,
|
||||
COL_ZOOM_TEXT1 = 0xd0ffffff,
|
||||
@ -70,33 +71,35 @@ public class Graph2dView extends View implements
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
onDraw(canvas);
|
||||
return Util.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||
return AndroidUtils2.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||
}
|
||||
|
||||
private void clearAllGraph() {
|
||||
for (int i = 0; i < GRAPHS_SIZE; ++i) {
|
||||
graphs[i].clear();
|
||||
private void clearAllGraphs() {
|
||||
for (GraphData graph : graphs) {
|
||||
graph.clear();
|
||||
}
|
||||
|
||||
while ( graphViewHelper.getFunctionPlotDefs().size() > graphs.size() ) {
|
||||
graphs.add(GraphData.newEmptyInstance());
|
||||
}
|
||||
}
|
||||
|
||||
public void setFunctions(List<Function> fs) {
|
||||
funcs.clear();
|
||||
for (Function f : fs) {
|
||||
int arity = f.arity();
|
||||
if (arity == 0 || arity == 1) {
|
||||
funcs.add(f);
|
||||
@Override
|
||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<FunctionPlotDef>emptyList());
|
||||
}
|
||||
|
||||
public void setFunctionPlotDefs(@NotNull List<FunctionPlotDef> functionPlotDefs) {
|
||||
|
||||
for (FunctionPlotDef 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!");
|
||||
}
|
||||
}
|
||||
clearAllGraph();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setFunction(Function f) {
|
||||
funcs.clear();
|
||||
if (f != null) {
|
||||
funcs.add(f);
|
||||
}
|
||||
clearAllGraph();
|
||||
this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs);
|
||||
clearAllGraphs();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@ -133,12 +136,12 @@ public class Graph2dView extends View implements
|
||||
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
||||
width = w;
|
||||
height = h;
|
||||
clearAllGraph();
|
||||
clearAllGraphs();
|
||||
// points = new float[w+w];
|
||||
}
|
||||
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (funcs.size() == 0) {
|
||||
if (graphViewHelper.getFunctionPlotDefs().size() == 0) {
|
||||
return;
|
||||
}
|
||||
if (scroller.computeScrollOffset()) {
|
||||
@ -184,9 +187,14 @@ public class Graph2dView extends View implements
|
||||
return up * up / (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
private void computeGraph(Function f, float minX, float maxX, float minY, float maxY, Data graph) {
|
||||
if (f.arity() == 0) {
|
||||
float v = (float) f.eval();
|
||||
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;
|
||||
}
|
||||
@ -217,7 +225,7 @@ public class Graph2dView extends View implements
|
||||
}
|
||||
}
|
||||
if (graph.empty()) {
|
||||
graph.push(minX, eval(f, minX));
|
||||
graph.push(minX, eval(function, minX));
|
||||
}
|
||||
float leftX, leftY;
|
||||
float rightX = graph.topX(), rightY = graph.topY();
|
||||
@ -230,7 +238,7 @@ public class Graph2dView extends View implements
|
||||
}
|
||||
if (next.empty()) {
|
||||
float x = leftX + maxStep;
|
||||
next.push(x, eval(f, x));
|
||||
next.push(x, eval(function, x));
|
||||
++nEval;
|
||||
}
|
||||
rightX = next.topX();
|
||||
@ -243,7 +251,7 @@ public class Graph2dView extends View implements
|
||||
|
||||
float dx = rightX - leftX;
|
||||
float middleX = (leftX + rightX) / 2;
|
||||
float middleY = eval(f, middleX);
|
||||
float middleY = eval(function, middleX);
|
||||
++nEval;
|
||||
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
||||
if (dx < minStep) {
|
||||
@ -289,30 +297,32 @@ public class Graph2dView extends View implements
|
||||
endGraph.clear();
|
||||
}
|
||||
|
||||
private static Path path = new Path();
|
||||
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();
|
||||
|
||||
private Path graphToPath(Data graph) {
|
||||
boolean first = true;
|
||||
int size = graph.size;
|
||||
float[] xs = graph.xs;
|
||||
float[] ys = graph.ys;
|
||||
path.rewind();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
float y = ys[i];
|
||||
float x = xs[i];
|
||||
// Calculator.log("path " + x + ' ' + y);
|
||||
if (y == y) { // !NaN
|
||||
if (first) {
|
||||
|
||||
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);
|
||||
first = false;
|
||||
newCurve = false;
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
} else {
|
||||
first = true;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static final float NTICKS = 15;
|
||||
@ -382,10 +392,10 @@ public class Graph2dView extends View implements
|
||||
float halfw = ywidth / 2;
|
||||
boundMinY = minY - halfw;
|
||||
boundMaxY = maxY + halfw;
|
||||
clearAllGraph();
|
||||
clearAllGraphs();
|
||||
}
|
||||
|
||||
canvas.drawColor(0xff000000);
|
||||
canvas.drawColor(graphViewHelper.getFunctionViewDef().getBackgroundColor());
|
||||
|
||||
paint.setStrokeWidth(0);
|
||||
paint.setAntiAlias(false);
|
||||
@ -412,34 +422,46 @@ public class Graph2dView extends View implements
|
||||
|
||||
final float tickSize = 3;
|
||||
final float y2 = y0 + tickSize;
|
||||
paint.setColor(COL_GRID);
|
||||
float step = stepFactor(gwidth);
|
||||
// Calculator.log("width " + gwidth + " step " + step);
|
||||
float v = ((int) (minX / step)) * step;
|
||||
textPaint.setColor(COL_TEXT);
|
||||
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);
|
||||
|
||||
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// AXIS
|
||||
|
||||
paint.setColor(COL_AXIS);
|
||||
paint.setColor(graphViewHelper.getFunctionViewDef().getAxisColor());
|
||||
if (drawYAxis) {
|
||||
canvas.drawLine(x0, 0, x0, height, paint);
|
||||
}
|
||||
@ -450,15 +472,23 @@ public class Graph2dView extends View implements
|
||||
matrix.postScale(scale, -scale);
|
||||
matrix.postTranslate(width / 2, height / 2);
|
||||
|
||||
paint.setStrokeWidth(0);
|
||||
paint.setAntiAlias(false);
|
||||
|
||||
int n = Math.min(funcs.size(), GRAPHS_SIZE);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
computeGraph(funcs.get(i), minX, maxX, boundMinY, boundMaxY, graphs[i]);
|
||||
Path path = graphToPath(graphs[i]);
|
||||
final List<FunctionPlotDef> functionPlotDefs = graphViewHelper.getFunctionPlotDefs();
|
||||
|
||||
// create path once
|
||||
final Path path = new Path();
|
||||
|
||||
for (int i = 0; i < functionPlotDefs.size(); i++) {
|
||||
final FunctionPlotDef fpd = functionPlotDefs.get(i);
|
||||
computeGraph(fpd.getFunction(), minX, maxX, boundMinY, boundMaxY, graphs.get(i));
|
||||
|
||||
graphToPath(graphs.get(i), path);
|
||||
|
||||
path.transform(matrix);
|
||||
paint.setColor(COL_GRAPH[i]);
|
||||
|
||||
fpd.getLineDef().applyToPaint(paint);
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
lastMinX = minX;
|
||||
@ -485,7 +515,7 @@ public class Graph2dView extends View implements
|
||||
}
|
||||
|
||||
private void invalidateGraphs() {
|
||||
clearAllGraph();
|
||||
clearAllGraphs();
|
||||
boundMinY = boundMaxY = 0;
|
||||
invalidate();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2009-2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import org.javia.arity.Function;
|
||||
|
||||
@ -12,41 +12,46 @@ import java.nio.FloatBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
class Graph3d {
|
||||
private final int N = Calculator.useHighQuality3d ? 36 : 24;
|
||||
|
||||
private final int N;
|
||||
private final boolean useHighQuality3d;
|
||||
private ShortBuffer verticeIdx;
|
||||
private FloatBuffer vertexBuf;
|
||||
private ByteBuffer colorBuf;
|
||||
private int vertexVbo, colorVbo, vertexElementVbo;
|
||||
private boolean useVBO;
|
||||
private int nVertex;
|
||||
|
||||
Graph3d(GL11 gl) {
|
||||
short[] b = new short[N*N];
|
||||
|
||||
Graph3d(GL11 gl, boolean useHighQuality3d) {
|
||||
this.useHighQuality3d = useHighQuality3d;
|
||||
this.N = useHighQuality3d ? 36 : 24;
|
||||
|
||||
short[] b = new short[N * N];
|
||||
int p = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
short v = 0;
|
||||
for (int j = 0; j < N; v += N+N, j+=2) {
|
||||
b[p++] = (short)(v+i);
|
||||
b[p++] = (short)(v+N+N-1-i);
|
||||
for (int j = 0; j < N; v += N + N, j += 2) {
|
||||
b[p++] = (short) (v + i);
|
||||
b[p++] = (short) (v + N + N - 1 - i);
|
||||
}
|
||||
v = (short) (N*(N-2));
|
||||
v = (short) (N * (N - 2));
|
||||
i++;
|
||||
for (int j = N-1; j >= 0; v -= N+N, j-=2) {
|
||||
b[p++] = (short)(v+N+N-1-i);
|
||||
b[p++] = (short)(v+i);
|
||||
}
|
||||
for (int j = N - 1; j >= 0; v -= N + N, j -= 2) {
|
||||
b[p++] = (short) (v + N + N - 1 - i);
|
||||
b[p++] = (short) (v + i);
|
||||
}
|
||||
}
|
||||
verticeIdx = buildBuffer(b);
|
||||
|
||||
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
|
||||
useVBO = extensions.indexOf("vertex_buffer_object") != -1;
|
||||
Calculator.log("VBOs support: " + useVBO + " version " + gl.glGetString(GL10.GL_VERSION));
|
||||
|
||||
//Calculator.log("VBOs support: " + useVBO + " version " + gl.glGetString(GL10.GL_VERSION));
|
||||
|
||||
if (useVBO) {
|
||||
int[] out = new int[3];
|
||||
gl.glGenBuffers(3, out, 0);
|
||||
gl.glGenBuffers(3, out, 0);
|
||||
vertexVbo = out[0];
|
||||
colorVbo = out[1];
|
||||
colorVbo = out[1];
|
||||
vertexElementVbo = out[2];
|
||||
}
|
||||
}
|
||||
@ -78,34 +83,34 @@ class Graph3d {
|
||||
}
|
||||
|
||||
public void update(GL11 gl, Function f, float zoom) {
|
||||
final int NTICK = Calculator.useHighQuality3d ? 5 : 0;
|
||||
final float size = 4*zoom;
|
||||
final int NTICK = useHighQuality3d ? 5 : 0;
|
||||
final float size = 4 * zoom;
|
||||
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
||||
|
||||
Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
||||
nVertex = N*N+6+8 + NTICK*6;
|
||||
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
||||
nVertex = N * N + 6 + 8 + NTICK * 6;
|
||||
int nFloats = nVertex * 3;
|
||||
float vertices[] = new float[nFloats];
|
||||
byte colors[] = new byte[nVertex << 2];
|
||||
if (f != null) {
|
||||
Calculator.log("Graph3d update");
|
||||
//Calculator.log("Graph3d update");
|
||||
float sizeX = maxX - minX;
|
||||
float sizeY = maxY - minY;
|
||||
float stepX = sizeX / (N-1);
|
||||
float stepY = sizeY / (N-1);
|
||||
float stepX = sizeX / (N - 1);
|
||||
float stepY = sizeY / (N - 1);
|
||||
int pos = 0;
|
||||
double sum = 0;
|
||||
float y = minY;
|
||||
float x = minX - stepX;
|
||||
int nRealPoints = 0;
|
||||
for (int i = 0; i < N; i++, y+=stepY) {
|
||||
for (int i = 0; i < N; i++, y += stepY) {
|
||||
float xinc = (i & 1) == 0 ? stepX : -stepX;
|
||||
x += xinc;
|
||||
for (int j = 0; j < N; ++j, x+=xinc, pos+=3) {
|
||||
for (int j = 0; j < N; ++j, x += xinc, pos += 3) {
|
||||
float z = (float) f.eval(x, y);
|
||||
vertices[pos] = x;
|
||||
vertices[pos+1] = y;
|
||||
vertices[pos+2] = z;
|
||||
vertices[pos + 1] = y;
|
||||
vertices[pos + 2] = z;
|
||||
if (z == z) { // not NAN
|
||||
sum += z * z;
|
||||
++nRealPoints;
|
||||
@ -117,125 +122,133 @@ class Graph3d {
|
||||
maxAbs = Math.min(maxAbs, 15);
|
||||
maxAbs = Math.max(maxAbs, .001f);
|
||||
|
||||
final int limitColor = N*N*4;
|
||||
for (int i = 0, j = 2; i < limitColor; i+=4, j+=3) {
|
||||
final int limitColor = N * N * 4;
|
||||
for (int i = 0, j = 2; i < limitColor; i += 4, j += 3) {
|
||||
float z = vertices[j];
|
||||
if (z == z) {
|
||||
final float a = z / maxAbs;
|
||||
final float abs = a < 0 ? -a : a;
|
||||
colors[i] = floatToByte(a);
|
||||
colors[i+1] = floatToByte(1-abs*.3f);
|
||||
colors[i+2] = floatToByte(-a);
|
||||
colors[i+3] = (byte) 255;
|
||||
colors[i] = floatToByte(a);
|
||||
colors[i + 1] = floatToByte(1 - abs * .3f);
|
||||
colors[i + 2] = floatToByte(-a);
|
||||
colors[i + 3] = (byte) 255;
|
||||
} else {
|
||||
vertices[j] = 0;
|
||||
z = 0;
|
||||
colors[i] = 0;
|
||||
colors[i+1] = 0;
|
||||
colors[i+2] = 0;
|
||||
colors[i+3] = 0;
|
||||
colors[i] = 0;
|
||||
colors[i + 1] = 0;
|
||||
colors[i + 2] = 0;
|
||||
colors[i + 3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int base = N*N*3;
|
||||
int colorBase = N*N*4;
|
||||
int base = N * N * 3;
|
||||
int colorBase = N * N * 4;
|
||||
int p = base;
|
||||
final int baseSize = 2;
|
||||
for (int i = -baseSize; i <= baseSize; i+=2*baseSize) {
|
||||
vertices[p] = i; vertices[p+1] = -baseSize; vertices[p+2] = 0;
|
||||
for (int i = -baseSize; i <= baseSize; i += 2 * baseSize) {
|
||||
vertices[p] = i;
|
||||
vertices[p + 1] = -baseSize;
|
||||
vertices[p + 2] = 0;
|
||||
p += 3;
|
||||
vertices[p] = i; vertices[p+1] = baseSize; vertices[p+2] = 0;
|
||||
vertices[p] = i;
|
||||
vertices[p + 1] = baseSize;
|
||||
vertices[p + 2] = 0;
|
||||
p += 3;
|
||||
vertices[p] = -baseSize; vertices[p+1] = i; vertices[p+2] = 0;
|
||||
vertices[p] = -baseSize;
|
||||
vertices[p + 1] = i;
|
||||
vertices[p + 2] = 0;
|
||||
p += 3;
|
||||
vertices[p] = baseSize; vertices[p+1] = i; vertices[p+2] = 0;
|
||||
vertices[p] = baseSize;
|
||||
vertices[p + 1] = i;
|
||||
vertices[p + 2] = 0;
|
||||
p += 3;
|
||||
}
|
||||
for (int i = colorBase; i < colorBase+8*4; i += 4) {
|
||||
for (int i = colorBase; i < colorBase + 8 * 4; i += 4) {
|
||||
colors[i] = 0;
|
||||
colors[i+1] = 0;
|
||||
colors[i+2] = (byte) 255;
|
||||
colors[i+3] = (byte) 255;
|
||||
colors[i + 1] = 0;
|
||||
colors[i + 2] = (byte) 255;
|
||||
colors[i + 3] = (byte) 255;
|
||||
}
|
||||
base += 8*3;
|
||||
colorBase += 8*4;
|
||||
base += 8 * 3;
|
||||
colorBase += 8 * 4;
|
||||
|
||||
final float unit = 2;
|
||||
final float axis[] = {
|
||||
0, 0, 0,
|
||||
unit, 0, 0,
|
||||
0, 0, 0,
|
||||
0, unit, 0,
|
||||
0, 0, 0,
|
||||
0, 0, unit,
|
||||
0, 0, 0,
|
||||
unit, 0, 0,
|
||||
0, 0, 0,
|
||||
0, unit, 0,
|
||||
0, 0, 0,
|
||||
0, 0, unit,
|
||||
};
|
||||
System.arraycopy(axis, 0, vertices, base, 6*3);
|
||||
for (int i = colorBase; i < colorBase+6*4; i+=4) {
|
||||
System.arraycopy(axis, 0, vertices, base, 6 * 3);
|
||||
for (int i = colorBase; i < colorBase + 6 * 4; i += 4) {
|
||||
colors[i] = (byte) 255;
|
||||
colors[i+1] = (byte) 255;
|
||||
colors[i+2] = (byte) 255;
|
||||
colors[i+3] = (byte) 255;
|
||||
}
|
||||
base += 6*3;
|
||||
colorBase += 6*4;
|
||||
colors[i + 1] = (byte) 255;
|
||||
colors[i + 2] = (byte) 255;
|
||||
colors[i + 3] = (byte) 255;
|
||||
}
|
||||
base += 6 * 3;
|
||||
colorBase += 6 * 4;
|
||||
|
||||
p = base;
|
||||
final float tick = .03f;
|
||||
final float offset = .01f;
|
||||
for (int i = 1; i <= NTICK; ++i) {
|
||||
vertices[p] = i-tick;
|
||||
vertices[p+1] = -offset;
|
||||
vertices[p+2] = -offset;
|
||||
vertices[p] = i - tick;
|
||||
vertices[p + 1] = -offset;
|
||||
vertices[p + 2] = -offset;
|
||||
|
||||
vertices[p+3] = i+tick;
|
||||
vertices[p+4] = offset;
|
||||
vertices[p+5] = offset;
|
||||
vertices[p + 3] = i + tick;
|
||||
vertices[p + 4] = offset;
|
||||
vertices[p + 5] = offset;
|
||||
p += 6;
|
||||
|
||||
vertices[p] = -offset;
|
||||
vertices[p+1] = i-tick;
|
||||
vertices[p+2] = -offset;
|
||||
vertices[p] = -offset;
|
||||
vertices[p + 1] = i - tick;
|
||||
vertices[p + 2] = -offset;
|
||||
|
||||
vertices[p+3] = offset;
|
||||
vertices[p+4] = i+tick;
|
||||
vertices[p+5] = offset;
|
||||
vertices[p + 3] = offset;
|
||||
vertices[p + 4] = i + tick;
|
||||
vertices[p + 5] = offset;
|
||||
p += 6;
|
||||
|
||||
vertices[p] = -offset;
|
||||
vertices[p+1] = -offset;
|
||||
vertices[p+2] = i-tick;
|
||||
vertices[p] = -offset;
|
||||
vertices[p + 1] = -offset;
|
||||
vertices[p + 2] = i - tick;
|
||||
|
||||
vertices[p+3] = offset;
|
||||
vertices[p+4] = offset;
|
||||
vertices[p+5] = i+tick;
|
||||
vertices[p + 3] = offset;
|
||||
vertices[p + 4] = offset;
|
||||
vertices[p + 5] = i + tick;
|
||||
p += 6;
|
||||
|
||||
|
||||
}
|
||||
for (int i = colorBase+NTICK*6*4-1; i >= colorBase; --i) {
|
||||
for (int i = colorBase + NTICK * 6 * 4 - 1; i >= colorBase; --i) {
|
||||
colors[i] = (byte) 255;
|
||||
}
|
||||
|
||||
vertexBuf = buildBuffer(vertices);
|
||||
colorBuf = buildBuffer(colors);
|
||||
colorBuf = buildBuffer(colors);
|
||||
|
||||
if (useVBO) {
|
||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
|
||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity()*4, vertexBuf, GL11.GL_STATIC_DRAW);
|
||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity() * 4, vertexBuf, GL11.GL_STATIC_DRAW);
|
||||
vertexBuf = null;
|
||||
|
||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
|
||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
|
||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
||||
colorBuf = null;
|
||||
|
||||
colorBuf = null;
|
||||
|
||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity()*2, verticeIdx, GL11.GL_STATIC_DRAW);
|
||||
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity() * 2, verticeIdx, GL11.GL_STATIC_DRAW);
|
||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private byte floatToByte(float v) {
|
||||
return (byte) (v <= 0 ? 0 : v >= 1 ? 255 : (int)(v*255));
|
||||
return (byte) (v <= 0 ? 0 : v >= 1 ? 255 : (int) (v * 255));
|
||||
}
|
||||
|
||||
public void draw(GL11 gl) {
|
||||
@ -249,16 +262,20 @@ class Graph3d {
|
||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
||||
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
|
||||
|
||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, 0);
|
||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N * N, GL10.GL_UNSIGNED_SHORT, 0);
|
||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
} else {
|
||||
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
|
||||
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
|
||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, verticeIdx);
|
||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N * N, GL10.GL_UNSIGNED_SHORT, verticeIdx);
|
||||
}
|
||||
final int N2 = N*N;
|
||||
final int N2 = N * N;
|
||||
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);
|
||||
gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);
|
||||
}
|
||||
|
||||
public boolean isUseHighQuality3d() {
|
||||
return useHighQuality3d;
|
||||
}
|
||||
}
|
@ -1,21 +1,23 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.content.Context;
|
||||
import android.opengl.Matrix;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.ZoomButtonsController;
|
||||
import org.javia.arity.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import javax.microedition.khronos.opengles.GL11;
|
||||
import java.util.List;
|
||||
|
||||
public class Graph3dView extends GLView implements
|
||||
GraphView,
|
||||
ZoomButtonsController.OnZoomListener,
|
||||
TouchHandler.TouchHandlerInterface {
|
||||
public class Graph3dView extends GLView implements GraphView {
|
||||
|
||||
private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5;
|
||||
|
||||
private float lastTouchX, lastTouchY;
|
||||
private TouchHandler touchHandler;
|
||||
@ -160,8 +162,16 @@ public class Graph3dView extends GLView implements
|
||||
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
|
||||
}
|
||||
|
||||
public void setFunction(Function f) {
|
||||
function = f;
|
||||
@Override
|
||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||
}
|
||||
|
||||
public void setFunctionPlotDefs(@NotNull List<FunctionPlotDef> functionPlotDefs) {
|
||||
if (functionPlotDefs.size() > 0) {
|
||||
function = functionPlotDefs.get(0).getFunction();
|
||||
} else {
|
||||
function = null;
|
||||
}
|
||||
zoomLevel = 1;
|
||||
isDirty = true;
|
||||
}
|
||||
@ -171,9 +181,9 @@ public class Graph3dView extends GLView implements
|
||||
gl.glDisable(GL10.GL_DITHER);
|
||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||
gl.glClearColor(0, 0, 0, 1);
|
||||
gl.glShadeModel(Calculator.useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
|
||||
gl.glShadeModel(useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
|
||||
gl.glDisable(GL10.GL_LIGHTING);
|
||||
graph = new Graph3d((GL11) gl);
|
||||
graph = new Graph3d((GL11) gl, useHighQuality3d);
|
||||
isDirty = true;
|
||||
angleX = .5f;
|
||||
angleY = 0;
|
||||
@ -195,9 +205,9 @@ public class Graph3dView extends GLView implements
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
if (fps.incFrame()) {
|
||||
/*if (fps.incFrame()) {
|
||||
Calculator.log("f/s " + fps.getValue());
|
||||
}
|
||||
}*/
|
||||
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
@ -244,6 +254,6 @@ public class Graph3dView extends GLView implements
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
b.append(m[i]).append(' ');
|
||||
}
|
||||
Calculator.log(name + ' ' + b.toString());
|
||||
//Calculator.log(name + ' ' + b.toString());
|
||||
}
|
||||
}
|
170
android-app/src/main/java/org/solovyev/android/calculator/plot/GraphData.java
Executable file
170
android-app/src/main/java/org/solovyev/android/calculator/plot/GraphData.java
Executable file
@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2009 Mihai Preda
|
||||
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class GraphData {
|
||||
|
||||
private int size = 0;
|
||||
|
||||
private int allocatedSize = 4;
|
||||
private float[] xs = new float[allocatedSize];
|
||||
private float[] ys = new float[allocatedSize];
|
||||
|
||||
private GraphData() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static GraphData newEmptyInstance() {
|
||||
return new GraphData();
|
||||
}
|
||||
|
||||
void swap(@NotNull GraphData that) {
|
||||
float savedXs[] = that.xs;
|
||||
float savedYs[] = that.ys;
|
||||
int savedSize = that.size;
|
||||
int savedAllocatedSize = that.allocatedSize;
|
||||
|
||||
that.xs = this.xs;
|
||||
that.ys = this.ys;
|
||||
that.size = this.size;
|
||||
that.allocatedSize = this.allocatedSize;
|
||||
|
||||
this.xs = savedXs;
|
||||
this.ys = savedYs;
|
||||
this.size = savedSize;
|
||||
this.allocatedSize = savedAllocatedSize;
|
||||
}
|
||||
|
||||
void push(float x, float y) {
|
||||
if (size >= allocatedSize) {
|
||||
makeSpace(size + 1);
|
||||
}
|
||||
|
||||
xs[size] = x;
|
||||
ys[size] = y;
|
||||
++size;
|
||||
}
|
||||
|
||||
private void makeSpace(int spaceSize) {
|
||||
int oldAllocatedSize = allocatedSize;
|
||||
while (spaceSize > allocatedSize) {
|
||||
allocatedSize += allocatedSize;
|
||||
}
|
||||
|
||||
if (oldAllocatedSize != allocatedSize) {
|
||||
float[] a = new float[allocatedSize];
|
||||
System.arraycopy(xs, 0, a, 0, this.size);
|
||||
xs = a;
|
||||
a = new float[allocatedSize];
|
||||
System.arraycopy(ys, 0, a, 0, this.size);
|
||||
ys = a;
|
||||
}
|
||||
}
|
||||
|
||||
float topX() {
|
||||
return xs[size - 1];
|
||||
}
|
||||
|
||||
float topY() {
|
||||
return ys[size - 1];
|
||||
}
|
||||
|
||||
float firstX() {
|
||||
return xs[0];
|
||||
}
|
||||
|
||||
float firstY() {
|
||||
return ys[0];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
--size;
|
||||
}
|
||||
|
||||
boolean empty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void eraseBefore(float x) {
|
||||
int pos = 0;
|
||||
while (pos < size && xs[pos] < x) {
|
||||
++pos;
|
||||
}
|
||||
--pos;
|
||||
if (pos > 0) {
|
||||
size -= pos;
|
||||
System.arraycopy(xs, pos, xs, 0, size);
|
||||
System.arraycopy(ys, pos, ys, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
void eraseAfter(float x) {
|
||||
int pos = size - 1;
|
||||
while (pos >= 0 && x < xs[pos]) {
|
||||
--pos;
|
||||
}
|
||||
++pos;
|
||||
if (pos < size - 1) {
|
||||
size = pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int findPosAfter(float x, float y) {
|
||||
int pos = 0;
|
||||
while (pos < size && xs[pos] <= x) {
|
||||
++pos;
|
||||
}
|
||||
if (Float.isNaN(y)) {
|
||||
while (pos < size && ys[pos] != ys[pos]) {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
// Calculator.log("pos " + pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
void append(GraphData d) {
|
||||
makeSpace(size + d.size);
|
||||
int pos = d.findPosAfter(xs[size - 1], ys[size - 1]);
|
||||
/*
|
||||
while (pos < d.size && d.xs[pos] <= last) {
|
||||
++pos;
|
||||
}
|
||||
if (last != last) {
|
||||
while (pos < d.size && d.ys[pos] != d.ys[pos]) {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
*/
|
||||
System.arraycopy(d.xs, pos, xs, size, d.size - pos);
|
||||
System.arraycopy(d.ys, pos, ys, size, d.size - pos);
|
||||
size += d.size - pos;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(size).append(": ");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
b.append(xs[i]).append(", ");
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public float[] getXs() {
|
||||
return xs;
|
||||
}
|
||||
|
||||
public float[] getYs() {
|
||||
return ys;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
}
|
@ -1,22 +1,25 @@
|
||||
// Copyright (C) 2009-2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import org.javia.arity.Function;
|
||||
import android.widget.ZoomButtonsController;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface GraphView {
|
||||
import java.util.List;
|
||||
|
||||
public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHandler.TouchHandlerInterface {
|
||||
|
||||
static final String SCREENSHOT_DIR = "/screenshots";
|
||||
|
||||
public void setFunction(Function f);
|
||||
public void init(@NotNull FunctionViewDef functionViewDef);
|
||||
|
||||
public void setFunctionPlotDefs(@NotNull List<FunctionPlotDef> functionPlotDefs);
|
||||
|
||||
public void onPause();
|
||||
public void onResume();
|
||||
|
||||
public String captureScreenshot();
|
||||
|
||||
void setId(int id);
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
@ -0,0 +1,59 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/5/13
|
||||
* Time: 8:06 PM
|
||||
*/
|
||||
public class GraphViewHelper {
|
||||
|
||||
@NotNull
|
||||
private FunctionViewDef functionViewDef = FunctionViewDef.newDefaultInstance();
|
||||
|
||||
@NotNull
|
||||
private List<FunctionPlotDef> functionPlotDefs = Collections.emptyList();
|
||||
|
||||
private GraphViewHelper() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static GraphViewHelper newDefaultInstance() {
|
||||
return new GraphViewHelper();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static GraphViewHelper newInstance(@NotNull FunctionViewDef functionViewDef,
|
||||
@NotNull List<FunctionPlotDef> functionPlotDefs) {
|
||||
final GraphViewHelper result = new GraphViewHelper();
|
||||
|
||||
result.functionViewDef = functionViewDef;
|
||||
result.functionPlotDefs = Collections.unmodifiableList(functionPlotDefs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GraphViewHelper copy(@NotNull List<FunctionPlotDef> newFunctionPlotDefs) {
|
||||
final GraphViewHelper result = new GraphViewHelper();
|
||||
|
||||
result.functionViewDef = functionViewDef;
|
||||
result.functionPlotDefs = Collections.unmodifiableList(newFunctionPlotDefs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<FunctionPlotDef> getFunctionPlotDefs() {
|
||||
return functionPlotDefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionViewDef getFunctionViewDef() {
|
||||
return functionViewDef;
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
// Copyright (C) 2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
class MotionEventWrap {
|
||||
private static final boolean IS_API_5 = Util.SDK_VERSION >= 5;
|
||||
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;
|
@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2009-2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2010 Mihai Preda
|
||||
|
||||
package arity.calculator;
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
class ZoomTracker {
|
||||
private float sx1, sy1, sx2, sy2;
|
Loading…
Reference in New Issue
Block a user