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.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.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: Solovyev_S
|
* User: Solovyev_S
|
||||||
* Date: 03.10.12
|
* Date: 03.10.12
|
||||||
@ -55,4 +63,43 @@ public final class AndroidUtils2 {
|
|||||||
int componentEnabledSetting = pm.getComponentEnabledSetting(new ComponentName(context, componentClass));
|
int componentEnabledSetting = pm.getComponentEnabledSetting(new ComponentName(context, componentClass));
|
||||||
return componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
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;
|
package arity.calculator;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -18,8 +17,9 @@ import android.widget.EditText;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import org.javia.arity.*;
|
import org.javia.arity.*;
|
||||||
import org.javia.arity.Util;
|
|
||||||
import org.solovyev.android.calculator.Locator;
|
import org.solovyev.android.calculator.Locator;
|
||||||
|
import org.solovyev.android.calculator.plot.Graph2dView;
|
||||||
|
import org.solovyev.android.calculator.plot.Graph3dView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -183,9 +183,6 @@ public class Calculator extends Activity implements TextWatcher,
|
|||||||
|
|
||||||
//OnClickListener
|
//OnClickListener
|
||||||
public void onClick(View target) {
|
public void onClick(View target) {
|
||||||
if (target == graphView || target == graph3dView) {
|
|
||||||
startActivity(new Intent(this, ShowGraph.class));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnItemClickListener
|
// OnItemClickListener
|
||||||
@ -323,7 +320,7 @@ public class Calculator extends Activity implements TextWatcher,
|
|||||||
showGraph(null);
|
showGraph(null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
graphView.setFunctions(auxFuncs);
|
//graphView.setFunctionPlotDefs(auxFuncs);
|
||||||
if (graphView.getVisibility() != View.VISIBLE) {
|
if (graphView.getVisibility() != View.VISIBLE) {
|
||||||
if (isAlphaVisible) {
|
if (isAlphaVisible) {
|
||||||
isAlphaVisible = false;
|
isAlphaVisible = false;
|
||||||
@ -376,7 +373,7 @@ public class Calculator extends Activity implements TextWatcher,
|
|||||||
} else {
|
} else {
|
||||||
// graphedFunction = f;
|
// graphedFunction = f;
|
||||||
if (f.arity() == 1) {
|
if (f.arity() == 1) {
|
||||||
graphView.setFunction(f);
|
//graphView.setFunctionPlotDefs(Arrays.asList(f));
|
||||||
if (graphView.getVisibility() != View.VISIBLE) {
|
if (graphView.getVisibility() != View.VISIBLE) {
|
||||||
if (isAlphaVisible) {
|
if (isAlphaVisible) {
|
||||||
isAlphaVisible = false;
|
isAlphaVisible = false;
|
||||||
@ -389,7 +386,7 @@ public class Calculator extends Activity implements TextWatcher,
|
|||||||
graphView.setVisibility(View.VISIBLE);
|
graphView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
graph3dView.setFunction(f);
|
//graph3dView.setFunctionPlotDefs(Arrays.asList(f));
|
||||||
if (graph3dView.getVisibility() != View.VISIBLE) {
|
if (graph3dView.getVisibility() != View.VISIBLE) {
|
||||||
if (isAlphaVisible) {
|
if (isAlphaVisible) {
|
||||||
isAlphaVisible = false;
|
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;
|
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.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import arity.calculator.Graph2dView;
|
|
||||||
import arity.calculator.Graph3dView;
|
|
||||||
import arity.calculator.GraphView;
|
|
||||||
import jscl.math.Generic;
|
import jscl.math.Generic;
|
||||||
import jscl.math.function.Constant;
|
import jscl.math.function.Constant;
|
||||||
import org.javia.arity.Complex;
|
|
||||||
import org.javia.arity.Function;
|
import org.javia.arity.Function;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.calculator.CalculatorPreferences;
|
||||||
import org.solovyev.android.calculator.R;
|
import org.solovyev.android.calculator.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -39,6 +39,12 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createGraphicalView(@NotNull View root, @NotNull PreparedInput preparedInput) {
|
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
|
// remove old
|
||||||
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
|
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 int arity = yVariable == null ? 1 : 2;
|
||||||
|
|
||||||
final List<Function> functions = new ArrayList<Function>();
|
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
||||||
functions.add(new Function() {
|
|
||||||
@Override
|
|
||||||
public int arity() {
|
|
||||||
return arity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||||
public double eval(double x) {
|
|
||||||
return PlotUtils.calculatorExpression(expression, xVariable, x).realPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (arity == 1) {
|
||||||
public double eval(double x, double y) {
|
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
graphContainer.addView((View) graphView);
|
||||||
} else {
|
} else {
|
||||||
onError();
|
onError();
|
||||||
@ -128,4 +117,79 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
this.graphView.onPause();
|
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 {
|
class FPS {
|
||||||
private int drawCnt;
|
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
|
// Copyright (C) 2009 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -9,12 +9,14 @@ import android.os.Message;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
|
import org.solovyev.android.AndroidUtils2;
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.*;
|
import javax.microedition.khronos.egl.*;
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11;
|
import javax.microedition.khronos.opengles.GL11;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
private boolean hasSurface;
|
private boolean hasSurface;
|
||||||
@ -33,8 +35,8 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
|
|
||||||
public String captureScreenshot() {
|
public String captureScreenshot() {
|
||||||
Bitmap bitmap = getRawPixels(gl, width, height);
|
Bitmap bitmap = getRawPixels(gl, width, height);
|
||||||
Util.bitmapBGRtoRGB(bitmap, width, height);
|
bitmapBGRtoRGB(bitmap, width, height);
|
||||||
return Util.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
return AndroidUtils2.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap getRawPixels(GL10 gl, int width, int height) {
|
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() {
|
public void onResume() {
|
||||||
Calculator.log("onResume " + this);
|
|
||||||
paused = false;
|
paused = false;
|
||||||
if (hasSurface) {
|
if (hasSurface) {
|
||||||
initGL();
|
initGL();
|
||||||
@ -81,7 +82,6 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
Calculator.log("onPause " + this);
|
|
||||||
deinitGL();
|
deinitGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,10 +125,8 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
if (hasSurface && !paused) {
|
if (hasSurface && !paused) {
|
||||||
onDrawFrame(gl);
|
onDrawFrame(gl);
|
||||||
if (!egl.eglSwapBuffers(display, surface)) {
|
if (!egl.eglSwapBuffers(display, surface)) {
|
||||||
Calculator.log("swapBuffers error " + egl.eglGetError());
|
|
||||||
}
|
}
|
||||||
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
|
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
|
||||||
Calculator.log("egl context lost " + this);
|
|
||||||
paused = true;
|
paused = true;
|
||||||
}
|
}
|
||||||
if (mIsLooping) {
|
if (mIsLooping) {
|
||||||
@ -138,11 +136,9 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
Calculator.log("surfaceCreated " + this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
Calculator.log("surfaceChanged " + format + ' ' + this);
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
boolean doInit = !hasSurface && !paused;
|
boolean doInit = !hasSurface && !paused;
|
||||||
@ -153,14 +149,12 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
Calculator.log("surfaceDestroyed " + this);
|
|
||||||
hasSurface = false;
|
hasSurface = false;
|
||||||
deinitGL();
|
deinitGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startLooping() {
|
public void startLooping() {
|
||||||
if (!mIsLooping) {
|
if (!mIsLooping) {
|
||||||
Calculator.log("start looping");
|
|
||||||
mIsLooping = true;
|
mIsLooping = true;
|
||||||
glDraw();
|
glDraw();
|
||||||
}
|
}
|
||||||
@ -168,7 +162,6 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
|
|
||||||
public void stopLooping() {
|
public void stopLooping() {
|
||||||
if (mIsLooping) {
|
if (mIsLooping) {
|
||||||
Calculator.log("stop looping");
|
|
||||||
mIsLooping = false;
|
mIsLooping = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,4 +173,18 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
public void requestDraw() {
|
public void requestDraw() {
|
||||||
handler.sendEmptyMessage(1);
|
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
|
// Copyright (C) 2009-2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.*;
|
import android.graphics.*;
|
||||||
@ -10,22 +11,29 @@ import android.view.View;
|
|||||||
import android.widget.Scroller;
|
import android.widget.Scroller;
|
||||||
import android.widget.ZoomButtonsController;
|
import android.widget.ZoomButtonsController;
|
||||||
import org.javia.arity.Function;
|
import org.javia.arity.Function;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.AndroidUtils2;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Graph2dView extends View implements
|
public class Graph2dView extends View implements GraphView {
|
||||||
GraphView,
|
|
||||||
ZoomButtonsController.OnZoomListener,
|
|
||||||
TouchHandler.TouchHandlerInterface {
|
|
||||||
|
|
||||||
private int width, height;
|
private int width, height;
|
||||||
private Matrix matrix = new Matrix();
|
private Matrix matrix = new Matrix();
|
||||||
private Paint paint = new Paint(), textPaint = new Paint(), fillPaint = new Paint();
|
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();
|
@NotNull
|
||||||
private Data graphs[] = {new Data(), new Data(), new Data(), new Data(), new Data()};
|
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
|
||||||
private static final int GRAPHS_SIZE = 5;
|
|
||||||
|
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 gwidth = 8;
|
||||||
private float currentX, currentY;
|
private float currentX, currentY;
|
||||||
private float lastMinX;
|
private float lastMinX;
|
||||||
@ -36,13 +44,6 @@ public class Graph2dView extends View implements
|
|||||||
private TouchHandler touchHandler;
|
private TouchHandler touchHandler;
|
||||||
private float lastTouchX, lastTouchY;
|
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
|
private static final int
|
||||||
COL_ZOOM = 0x40ffffff,
|
COL_ZOOM = 0x40ffffff,
|
||||||
COL_ZOOM_TEXT1 = 0xd0ffffff,
|
COL_ZOOM_TEXT1 = 0xd0ffffff,
|
||||||
@ -70,33 +71,35 @@ public class Graph2dView extends View implements
|
|||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
onDraw(canvas);
|
onDraw(canvas);
|
||||||
return Util.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
return AndroidUtils2.saveBitmap(bitmap, GraphView.SCREENSHOT_DIR, "calculator");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearAllGraph() {
|
private void clearAllGraphs() {
|
||||||
for (int i = 0; i < GRAPHS_SIZE; ++i) {
|
for (GraphData graph : graphs) {
|
||||||
graphs[i].clear();
|
graph.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( graphViewHelper.getFunctionPlotDefs().size() > graphs.size() ) {
|
||||||
|
graphs.add(GraphData.newEmptyInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunctions(List<Function> fs) {
|
@Override
|
||||||
funcs.clear();
|
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||||
for (Function f : fs) {
|
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<FunctionPlotDef>emptyList());
|
||||||
int arity = f.arity();
|
}
|
||||||
if (arity == 0 || arity == 1) {
|
|
||||||
funcs.add(f);
|
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) {
|
this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs);
|
||||||
funcs.clear();
|
clearAllGraphs();
|
||||||
if (f != null) {
|
|
||||||
funcs.add(f);
|
|
||||||
}
|
|
||||||
clearAllGraph();
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,12 +136,12 @@ public class Graph2dView extends View implements
|
|||||||
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
protected void onSizeChanged(int w, int h, int ow, int oh) {
|
||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
clearAllGraph();
|
clearAllGraphs();
|
||||||
// points = new float[w+w];
|
// points = new float[w+w];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
if (funcs.size() == 0) {
|
if (graphViewHelper.getFunctionPlotDefs().size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scroller.computeScrollOffset()) {
|
if (scroller.computeScrollOffset()) {
|
||||||
@ -184,9 +187,14 @@ public class Graph2dView extends View implements
|
|||||||
return up * up / (dx * dx + dy * dy);
|
return up * up / (dx * dx + dy * dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeGraph(Function f, float minX, float maxX, float minY, float maxY, Data graph) {
|
private void computeGraph(@NotNull Function function,
|
||||||
if (f.arity() == 0) {
|
float minX,
|
||||||
float v = (float) f.eval();
|
float maxX,
|
||||||
|
float minY,
|
||||||
|
float maxY,
|
||||||
|
@NotNull GraphData graph) {
|
||||||
|
if (function.arity() == 0) {
|
||||||
|
float v = (float) function.eval();
|
||||||
if (v < -10000f) {
|
if (v < -10000f) {
|
||||||
v = -10000f;
|
v = -10000f;
|
||||||
}
|
}
|
||||||
@ -217,7 +225,7 @@ public class Graph2dView extends View implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (graph.empty()) {
|
if (graph.empty()) {
|
||||||
graph.push(minX, eval(f, minX));
|
graph.push(minX, eval(function, minX));
|
||||||
}
|
}
|
||||||
float leftX, leftY;
|
float leftX, leftY;
|
||||||
float rightX = graph.topX(), rightY = graph.topY();
|
float rightX = graph.topX(), rightY = graph.topY();
|
||||||
@ -230,7 +238,7 @@ public class Graph2dView extends View implements
|
|||||||
}
|
}
|
||||||
if (next.empty()) {
|
if (next.empty()) {
|
||||||
float x = leftX + maxStep;
|
float x = leftX + maxStep;
|
||||||
next.push(x, eval(f, x));
|
next.push(x, eval(function, x));
|
||||||
++nEval;
|
++nEval;
|
||||||
}
|
}
|
||||||
rightX = next.topX();
|
rightX = next.topX();
|
||||||
@ -243,7 +251,7 @@ public class Graph2dView extends View implements
|
|||||||
|
|
||||||
float dx = rightX - leftX;
|
float dx = rightX - leftX;
|
||||||
float middleX = (leftX + rightX) / 2;
|
float middleX = (leftX + rightX) / 2;
|
||||||
float middleY = eval(f, middleX);
|
float middleY = eval(function, middleX);
|
||||||
++nEval;
|
++nEval;
|
||||||
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
|
||||||
if (dx < minStep) {
|
if (dx < minStep) {
|
||||||
@ -289,30 +297,32 @@ public class Graph2dView extends View implements
|
|||||||
endGraph.clear();
|
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();
|
path.rewind();
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
float y = ys[i];
|
boolean newCurve = true;
|
||||||
float x = xs[i];
|
|
||||||
// Calculator.log("path " + x + ' ' + y);
|
for (int i = 0; i < size; i++) {
|
||||||
if (y == y) { // !NaN
|
|
||||||
if (first) {
|
final float y = ys[i];
|
||||||
|
final float x = xs[i];
|
||||||
|
|
||||||
|
if (y != y) {
|
||||||
|
newCurve = true;
|
||||||
|
} else { // !NaN
|
||||||
|
if (newCurve) {
|
||||||
path.moveTo(x, y);
|
path.moveTo(x, y);
|
||||||
first = false;
|
newCurve = false;
|
||||||
} else {
|
} else {
|
||||||
path.lineTo(x, y);
|
path.lineTo(x, y);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
first = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final float NTICKS = 15;
|
private static final float NTICKS = 15;
|
||||||
@ -382,10 +392,10 @@ public class Graph2dView extends View implements
|
|||||||
float halfw = ywidth / 2;
|
float halfw = ywidth / 2;
|
||||||
boundMinY = minY - halfw;
|
boundMinY = minY - halfw;
|
||||||
boundMaxY = maxY + halfw;
|
boundMaxY = maxY + halfw;
|
||||||
clearAllGraph();
|
clearAllGraphs();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.drawColor(0xff000000);
|
canvas.drawColor(graphViewHelper.getFunctionViewDef().getBackgroundColor());
|
||||||
|
|
||||||
paint.setStrokeWidth(0);
|
paint.setStrokeWidth(0);
|
||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
@ -412,34 +422,46 @@ public class Graph2dView extends View implements
|
|||||||
|
|
||||||
final float tickSize = 3;
|
final float tickSize = 3;
|
||||||
final float y2 = y0 + tickSize;
|
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;
|
// GRID
|
||||||
textPaint.setColor(COL_TEXT);
|
|
||||||
textPaint.setTextSize(12);
|
paint.setPathEffect(new DashPathEffect(new float[]{5, 10}, 0));
|
||||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
paint.setColor(graphViewHelper.getFunctionViewDef().getGridColor());
|
||||||
float stepScale = step * scale;
|
|
||||||
for (float x = (v - minX) * scale; x <= width; x += stepScale, v += step) {
|
float step = stepFactor(gwidth);
|
||||||
canvas.drawLine(x, 0, x, height, paint);
|
// Calculator.log("width " + gwidth + " step " + step);
|
||||||
if (!(-.001f < v && v < .001f)) {
|
float v = ((int) (minX / step)) * step;
|
||||||
StringBuilder b = format(v);
|
textPaint.setColor(graphViewHelper.getFunctionViewDef().getAxisLabelsColor());
|
||||||
canvas.drawText(b, 0, b.length(), x, y2 + 10, textPaint);
|
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;
|
// AXIS
|
||||||
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.setColor(COL_AXIS);
|
paint.setColor(graphViewHelper.getFunctionViewDef().getAxisColor());
|
||||||
if (drawYAxis) {
|
if (drawYAxis) {
|
||||||
canvas.drawLine(x0, 0, x0, height, paint);
|
canvas.drawLine(x0, 0, x0, height, paint);
|
||||||
}
|
}
|
||||||
@ -450,15 +472,23 @@ public class Graph2dView extends View implements
|
|||||||
matrix.postScale(scale, -scale);
|
matrix.postScale(scale, -scale);
|
||||||
matrix.postTranslate(width / 2, height / 2);
|
matrix.postTranslate(width / 2, height / 2);
|
||||||
|
|
||||||
paint.setStrokeWidth(0);
|
|
||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
|
|
||||||
int n = Math.min(funcs.size(), GRAPHS_SIZE);
|
final List<FunctionPlotDef> functionPlotDefs = graphViewHelper.getFunctionPlotDefs();
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
computeGraph(funcs.get(i), minX, maxX, boundMinY, boundMaxY, graphs[i]);
|
// create path once
|
||||||
Path path = graphToPath(graphs[i]);
|
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);
|
path.transform(matrix);
|
||||||
paint.setColor(COL_GRAPH[i]);
|
|
||||||
|
fpd.getLineDef().applyToPaint(paint);
|
||||||
|
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
}
|
}
|
||||||
lastMinX = minX;
|
lastMinX = minX;
|
||||||
@ -485,7 +515,7 @@ public class Graph2dView extends View implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void invalidateGraphs() {
|
private void invalidateGraphs() {
|
||||||
clearAllGraph();
|
clearAllGraphs();
|
||||||
boundMinY = boundMaxY = 0;
|
boundMinY = boundMaxY = 0;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (C) 2009-2010 Mihai Preda
|
// Copyright (C) 2009-2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import org.javia.arity.Function;
|
import org.javia.arity.Function;
|
||||||
|
|
||||||
@ -12,41 +12,46 @@ import java.nio.FloatBuffer;
|
|||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
class Graph3d {
|
class Graph3d {
|
||||||
private final int N = Calculator.useHighQuality3d ? 36 : 24;
|
|
||||||
|
private final int N;
|
||||||
|
private final boolean useHighQuality3d;
|
||||||
private ShortBuffer verticeIdx;
|
private ShortBuffer verticeIdx;
|
||||||
private FloatBuffer vertexBuf;
|
private FloatBuffer vertexBuf;
|
||||||
private ByteBuffer colorBuf;
|
private ByteBuffer colorBuf;
|
||||||
private int vertexVbo, colorVbo, vertexElementVbo;
|
private int vertexVbo, colorVbo, vertexElementVbo;
|
||||||
private boolean useVBO;
|
private boolean useVBO;
|
||||||
private int nVertex;
|
private int nVertex;
|
||||||
|
|
||||||
Graph3d(GL11 gl) {
|
Graph3d(GL11 gl, boolean useHighQuality3d) {
|
||||||
short[] b = new short[N*N];
|
this.useHighQuality3d = useHighQuality3d;
|
||||||
|
this.N = useHighQuality3d ? 36 : 24;
|
||||||
|
|
||||||
|
short[] b = new short[N * N];
|
||||||
int p = 0;
|
int p = 0;
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
short v = 0;
|
short v = 0;
|
||||||
for (int j = 0; j < N; v += N+N, j+=2) {
|
for (int j = 0; j < N; v += N + N, j += 2) {
|
||||||
b[p++] = (short)(v+i);
|
b[p++] = (short) (v + i);
|
||||||
b[p++] = (short)(v+N+N-1-i);
|
b[p++] = (short) (v + N + N - 1 - i);
|
||||||
}
|
}
|
||||||
v = (short) (N*(N-2));
|
v = (short) (N * (N - 2));
|
||||||
i++;
|
i++;
|
||||||
for (int j = N-1; j >= 0; v -= N+N, j-=2) {
|
for (int j = N - 1; j >= 0; v -= N + N, j -= 2) {
|
||||||
b[p++] = (short)(v+N+N-1-i);
|
b[p++] = (short) (v + N + N - 1 - i);
|
||||||
b[p++] = (short)(v+i);
|
b[p++] = (short) (v + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
verticeIdx = buildBuffer(b);
|
verticeIdx = buildBuffer(b);
|
||||||
|
|
||||||
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
|
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
|
||||||
useVBO = extensions.indexOf("vertex_buffer_object") != -1;
|
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) {
|
if (useVBO) {
|
||||||
int[] out = new int[3];
|
int[] out = new int[3];
|
||||||
gl.glGenBuffers(3, out, 0);
|
gl.glGenBuffers(3, out, 0);
|
||||||
vertexVbo = out[0];
|
vertexVbo = out[0];
|
||||||
colorVbo = out[1];
|
colorVbo = out[1];
|
||||||
vertexElementVbo = out[2];
|
vertexElementVbo = out[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,34 +83,34 @@ class Graph3d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update(GL11 gl, Function f, float zoom) {
|
public void update(GL11 gl, Function f, float zoom) {
|
||||||
final int NTICK = Calculator.useHighQuality3d ? 5 : 0;
|
final int NTICK = useHighQuality3d ? 5 : 0;
|
||||||
final float size = 4*zoom;
|
final float size = 4 * zoom;
|
||||||
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
||||||
|
|
||||||
Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
||||||
nVertex = N*N+6+8 + NTICK*6;
|
nVertex = N * N + 6 + 8 + NTICK * 6;
|
||||||
int nFloats = nVertex * 3;
|
int nFloats = nVertex * 3;
|
||||||
float vertices[] = new float[nFloats];
|
float vertices[] = new float[nFloats];
|
||||||
byte colors[] = new byte[nVertex << 2];
|
byte colors[] = new byte[nVertex << 2];
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
Calculator.log("Graph3d update");
|
//Calculator.log("Graph3d update");
|
||||||
float sizeX = maxX - minX;
|
float sizeX = maxX - minX;
|
||||||
float sizeY = maxY - minY;
|
float sizeY = maxY - minY;
|
||||||
float stepX = sizeX / (N-1);
|
float stepX = sizeX / (N - 1);
|
||||||
float stepY = sizeY / (N-1);
|
float stepY = sizeY / (N - 1);
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
float y = minY;
|
float y = minY;
|
||||||
float x = minX - stepX;
|
float x = minX - stepX;
|
||||||
int nRealPoints = 0;
|
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;
|
float xinc = (i & 1) == 0 ? stepX : -stepX;
|
||||||
x += xinc;
|
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);
|
float z = (float) f.eval(x, y);
|
||||||
vertices[pos] = x;
|
vertices[pos] = x;
|
||||||
vertices[pos+1] = y;
|
vertices[pos + 1] = y;
|
||||||
vertices[pos+2] = z;
|
vertices[pos + 2] = z;
|
||||||
if (z == z) { // not NAN
|
if (z == z) { // not NAN
|
||||||
sum += z * z;
|
sum += z * z;
|
||||||
++nRealPoints;
|
++nRealPoints;
|
||||||
@ -117,125 +122,133 @@ class Graph3d {
|
|||||||
maxAbs = Math.min(maxAbs, 15);
|
maxAbs = Math.min(maxAbs, 15);
|
||||||
maxAbs = Math.max(maxAbs, .001f);
|
maxAbs = Math.max(maxAbs, .001f);
|
||||||
|
|
||||||
final int limitColor = N*N*4;
|
final int limitColor = N * N * 4;
|
||||||
for (int i = 0, j = 2; i < limitColor; i+=4, j+=3) {
|
for (int i = 0, j = 2; i < limitColor; i += 4, j += 3) {
|
||||||
float z = vertices[j];
|
float z = vertices[j];
|
||||||
if (z == z) {
|
if (z == z) {
|
||||||
final float a = z / maxAbs;
|
final float a = z / maxAbs;
|
||||||
final float abs = a < 0 ? -a : a;
|
final float abs = a < 0 ? -a : a;
|
||||||
colors[i] = floatToByte(a);
|
colors[i] = floatToByte(a);
|
||||||
colors[i+1] = floatToByte(1-abs*.3f);
|
colors[i + 1] = floatToByte(1 - abs * .3f);
|
||||||
colors[i+2] = floatToByte(-a);
|
colors[i + 2] = floatToByte(-a);
|
||||||
colors[i+3] = (byte) 255;
|
colors[i + 3] = (byte) 255;
|
||||||
} else {
|
} else {
|
||||||
vertices[j] = 0;
|
vertices[j] = 0;
|
||||||
z = 0;
|
z = 0;
|
||||||
colors[i] = 0;
|
colors[i] = 0;
|
||||||
colors[i+1] = 0;
|
colors[i + 1] = 0;
|
||||||
colors[i+2] = 0;
|
colors[i + 2] = 0;
|
||||||
colors[i+3] = 0;
|
colors[i + 3] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int base = N*N*3;
|
int base = N * N * 3;
|
||||||
int colorBase = N*N*4;
|
int colorBase = N * N * 4;
|
||||||
int p = base;
|
int p = base;
|
||||||
final int baseSize = 2;
|
final int baseSize = 2;
|
||||||
for (int i = -baseSize; i <= baseSize; i+=2*baseSize) {
|
for (int i = -baseSize; i <= baseSize; i += 2 * baseSize) {
|
||||||
vertices[p] = i; vertices[p+1] = -baseSize; vertices[p+2] = 0;
|
vertices[p] = i;
|
||||||
|
vertices[p + 1] = -baseSize;
|
||||||
|
vertices[p + 2] = 0;
|
||||||
p += 3;
|
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;
|
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;
|
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;
|
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] = 0;
|
||||||
colors[i+1] = 0;
|
colors[i + 1] = 0;
|
||||||
colors[i+2] = (byte) 255;
|
colors[i + 2] = (byte) 255;
|
||||||
colors[i+3] = (byte) 255;
|
colors[i + 3] = (byte) 255;
|
||||||
}
|
}
|
||||||
base += 8*3;
|
base += 8 * 3;
|
||||||
colorBase += 8*4;
|
colorBase += 8 * 4;
|
||||||
|
|
||||||
final float unit = 2;
|
final float unit = 2;
|
||||||
final float axis[] = {
|
final float axis[] = {
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
unit, 0, 0,
|
unit, 0, 0,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0, unit, 0,
|
0, unit, 0,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0, 0, unit,
|
0, 0, unit,
|
||||||
};
|
};
|
||||||
System.arraycopy(axis, 0, vertices, base, 6*3);
|
System.arraycopy(axis, 0, vertices, base, 6 * 3);
|
||||||
for (int i = colorBase; i < colorBase+6*4; i+=4) {
|
for (int i = colorBase; i < colorBase + 6 * 4; i += 4) {
|
||||||
colors[i] = (byte) 255;
|
colors[i] = (byte) 255;
|
||||||
colors[i+1] = (byte) 255;
|
colors[i + 1] = (byte) 255;
|
||||||
colors[i+2] = (byte) 255;
|
colors[i + 2] = (byte) 255;
|
||||||
colors[i+3] = (byte) 255;
|
colors[i + 3] = (byte) 255;
|
||||||
}
|
}
|
||||||
base += 6*3;
|
base += 6 * 3;
|
||||||
colorBase += 6*4;
|
colorBase += 6 * 4;
|
||||||
|
|
||||||
p = base;
|
p = base;
|
||||||
final float tick = .03f;
|
final float tick = .03f;
|
||||||
final float offset = .01f;
|
final float offset = .01f;
|
||||||
for (int i = 1; i <= NTICK; ++i) {
|
for (int i = 1; i <= NTICK; ++i) {
|
||||||
vertices[p] = i-tick;
|
vertices[p] = i - tick;
|
||||||
vertices[p+1] = -offset;
|
vertices[p + 1] = -offset;
|
||||||
vertices[p+2] = -offset;
|
vertices[p + 2] = -offset;
|
||||||
|
|
||||||
vertices[p+3] = i+tick;
|
vertices[p + 3] = i + tick;
|
||||||
vertices[p+4] = offset;
|
vertices[p + 4] = offset;
|
||||||
vertices[p+5] = offset;
|
vertices[p + 5] = offset;
|
||||||
p += 6;
|
p += 6;
|
||||||
|
|
||||||
vertices[p] = -offset;
|
vertices[p] = -offset;
|
||||||
vertices[p+1] = i-tick;
|
vertices[p + 1] = i - tick;
|
||||||
vertices[p+2] = -offset;
|
vertices[p + 2] = -offset;
|
||||||
|
|
||||||
vertices[p+3] = offset;
|
vertices[p + 3] = offset;
|
||||||
vertices[p+4] = i+tick;
|
vertices[p + 4] = i + tick;
|
||||||
vertices[p+5] = offset;
|
vertices[p + 5] = offset;
|
||||||
p += 6;
|
p += 6;
|
||||||
|
|
||||||
vertices[p] = -offset;
|
vertices[p] = -offset;
|
||||||
vertices[p+1] = -offset;
|
vertices[p + 1] = -offset;
|
||||||
vertices[p+2] = i-tick;
|
vertices[p + 2] = i - tick;
|
||||||
|
|
||||||
vertices[p+3] = offset;
|
vertices[p + 3] = offset;
|
||||||
vertices[p+4] = offset;
|
vertices[p + 4] = offset;
|
||||||
vertices[p+5] = i+tick;
|
vertices[p + 5] = i + tick;
|
||||||
p += 6;
|
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;
|
colors[i] = (byte) 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexBuf = buildBuffer(vertices);
|
vertexBuf = buildBuffer(vertices);
|
||||||
colorBuf = buildBuffer(colors);
|
colorBuf = buildBuffer(colors);
|
||||||
|
|
||||||
if (useVBO) {
|
if (useVBO) {
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
|
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;
|
vertexBuf = null;
|
||||||
|
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
|
||||||
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
|
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
|
||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
||||||
colorBuf = null;
|
colorBuf = null;
|
||||||
|
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
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);
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte floatToByte(float v) {
|
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) {
|
public void draw(GL11 gl) {
|
||||||
@ -249,16 +262,20 @@ class Graph3d {
|
|||||||
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
|
||||||
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
|
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
|
||||||
|
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
|
||||||
gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, 0);
|
gl.glDrawElements(GL10.GL_LINE_STRIP, N * N, GL10.GL_UNSIGNED_SHORT, 0);
|
||||||
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
} else {
|
} else {
|
||||||
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
|
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
|
||||||
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
|
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_LINE_STRIP, 0, N2);
|
||||||
gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);
|
gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseHighQuality3d() {
|
||||||
|
return useHighQuality3d;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,21 +1,23 @@
|
|||||||
// Copyright (C) 2009 Mihai Preda
|
// Copyright (C) 2009 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.opengl.Matrix;
|
import android.opengl.Matrix;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.widget.ZoomButtonsController;
|
import android.widget.ZoomButtonsController;
|
||||||
import org.javia.arity.Function;
|
import org.javia.arity.Function;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11;
|
import javax.microedition.khronos.opengles.GL11;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Graph3dView extends GLView implements
|
public class Graph3dView extends GLView implements GraphView {
|
||||||
GraphView,
|
|
||||||
ZoomButtonsController.OnZoomListener,
|
private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5;
|
||||||
TouchHandler.TouchHandlerInterface {
|
|
||||||
|
|
||||||
private float lastTouchX, lastTouchY;
|
private float lastTouchX, lastTouchY;
|
||||||
private TouchHandler touchHandler;
|
private TouchHandler touchHandler;
|
||||||
@ -160,8 +162,16 @@ public class Graph3dView extends GLView implements
|
|||||||
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
|
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunction(Function f) {
|
@Override
|
||||||
function = f;
|
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;
|
zoomLevel = 1;
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
}
|
}
|
||||||
@ -171,9 +181,9 @@ public class Graph3dView extends GLView implements
|
|||||||
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);
|
||||||
gl.glClearColor(0, 0, 0, 1);
|
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);
|
gl.glDisable(GL10.GL_LIGHTING);
|
||||||
graph = new Graph3d((GL11) gl);
|
graph = new Graph3d((GL11) gl, useHighQuality3d);
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
angleX = .5f;
|
angleX = .5f;
|
||||||
angleY = 0;
|
angleY = 0;
|
||||||
@ -195,9 +205,9 @@ public class Graph3dView extends GLView implements
|
|||||||
isDirty = false;
|
isDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fps.incFrame()) {
|
/*if (fps.incFrame()) {
|
||||||
Calculator.log("f/s " + fps.getValue());
|
Calculator.log("f/s " + fps.getValue());
|
||||||
}
|
}*/
|
||||||
|
|
||||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||||
@ -244,6 +254,6 @@ public class Graph3dView extends GLView implements
|
|||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
b.append(m[i]).append(' ');
|
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
|
// 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";
|
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 onPause();
|
||||||
public void onResume();
|
public void onResume();
|
||||||
|
|
||||||
public String captureScreenshot();
|
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
|
// Copyright (C) 2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
class MotionEventWrap {
|
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) {
|
static int getPointerCount(MotionEvent event) {
|
||||||
return IS_API_5 ? MotionEventWrapNew.getPointerCount(event) : 1;
|
return IS_API_5 ? MotionEventWrapNew.getPointerCount(event) : 1;
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (C) 2010 Mihai Preda
|
// Copyright (C) 2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (C) 2009-2010 Mihai Preda
|
// Copyright (C) 2009-2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (C) 2010 Mihai Preda
|
// Copyright (C) 2010 Mihai Preda
|
||||||
|
|
||||||
package arity.calculator;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
class ZoomTracker {
|
class ZoomTracker {
|
||||||
private float sx1, sy1, sx2, sy2;
|
private float sx1, sy1, sx2, sy2;
|
Loading…
Reference in New Issue
Block a user