new plotter

This commit is contained in:
Sergey Solovyev 2013-01-19 23:59:14 +04:00
parent 3f76f61c4b
commit cc5d74b54b
12 changed files with 370 additions and 253 deletions

View File

@ -19,6 +19,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.app.SherlockFragmentActivity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -31,7 +32,7 @@ import org.solovyev.common.equals.EqualsTool;
import org.solovyev.common.history.HistoryAction; import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;
public class CalculatorActivity extends SherlockFragmentActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public class CalculatorActivity extends SherlockFragmentActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener {
@NotNull @NotNull
public static final String TAG = CalculatorActivity.class.getSimpleName(); public static final String TAG = CalculatorActivity.class.getSimpleName();
@ -57,7 +58,7 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
activityHelper.logDebug("super.onCreate"); activityHelper.logDebug("super.onCreate");
if (findViewById(R.id.main_second_pane) != null) { if (isMultiPane()) {
activityHelper.addTab(this, CalculatorFragmentType.history, null, R.id.main_second_pane); activityHelper.addTab(this, CalculatorFragmentType.history, null, R.id.main_second_pane);
activityHelper.addTab(this, CalculatorFragmentType.saved_history, null, R.id.main_second_pane); activityHelper.addTab(this, CalculatorFragmentType.saved_history, null, R.id.main_second_pane);
activityHelper.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane); activityHelper.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane);
@ -89,6 +90,10 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
} }
} }
private boolean isMultiPane() {
return findViewById(R.id.main_second_pane) != null;
}
@NotNull @NotNull
private AndroidCalculator getCalculator() { private AndroidCalculator getCalculator() {
return ((AndroidCalculator) Locator.getInstance().getCalculator()); return ((AndroidCalculator) Locator.getInstance().getCalculator());
@ -321,4 +326,28 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
buttonPressed(CalculatorSpecialButton.like); buttonPressed(CalculatorSpecialButton.like);
} }
@Override
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case plot_graph:
Threads.tryRunOnUiThread(this, new Runnable() {
@Override
public void run() {
if ( isMultiPane() ) {
final ActionBar.Tab selectedTab = getSupportActionBar().getSelectedTab();
if ( selectedTab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(selectedTab.getTag()) ) {
// do nothing - fragment shown and already registered for plot updates
} else {
// otherwise - open fragment
activityHelper.selectTab(CalculatorActivity.this, CalculatorFragmentType.plotter);
}
} else {
// start new activity
CalculatorActivityLauncher.plotGraph(CalculatorActivity.this);
}
}
});
break;
}
}
} }

View File

@ -61,4 +61,6 @@ public interface CalculatorActivityHelper {
void processButtons(@NotNull Activity activity, @NotNull View root); void processButtons(@NotNull Activity activity, @NotNull View root);
void logError(@NotNull String message); void logError(@NotNull String message);
void selectTab(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType);
} }

View File

@ -228,6 +228,18 @@ public class CalculatorActivityHelperImpl extends AbstractCalculatorHelper imple
} }
} }
@Override
public void selectTab(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType) {
final ActionBar actionBar = activity.getSupportActionBar();
for (int i = 0; i < actionBar.getTabCount(); i++) {
final ActionBar.Tab tab = actionBar.getTabAt(i);
if ( tab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(tab.getTag()) ) {
actionBar.setSelectedNavigationItem(i);
break;
}
}
}
@Override @Override
public int getLayoutId() { public int getLayoutId() {
return layoutId; return layoutId;

View File

@ -233,14 +233,6 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
} }
}); });
break; break;
case plot_graph:
App.getInstance().getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
plotGraph(context);
}
});
break;
case show_evaluation_error: case show_evaluation_error:
final String errorMessage = (String) data; final String errorMessage = (String) data;
if (errorMessage != null) { if (errorMessage != null) {

View File

@ -136,14 +136,14 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
Threads.tryRunOnUiThread(activity, new Runnable() { Threads.tryRunOnUiThread(activity, new Runnable() {
@Override @Override
public void run() { public void run() {
activity.invalidateOptionsMenu();
createChart(plotData); createChart(plotData);
final View view = getView(); final View view = getView();
if (view != null) { if (view != null) {
createGraphicalView(view, plotData); createGraphicalView(view, plotData);
} }
activity.invalidateOptionsMenu();
} }
}); });
} }
@ -231,6 +231,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
}; };
menuItems.add(captureScreenshotMenuItem); menuItems.add(captureScreenshotMenuItem);
final boolean plotRangeVisible = !plotData.isPlot3d();
final boolean plot3dVisible = !plotData.isPlot3d() && is3dPlotSupported(); final boolean plot3dVisible = !plotData.isPlot3d() && is3dPlotSupported();
final boolean plot2dVisible = plotData.isPlot3d() && Locator.getInstance().getPlotter().is2dPlotPossible(); final boolean plot2dVisible = plotData.isPlot3d() && Locator.getInstance().getPlotter().is2dPlotPossible();
final boolean captureScreenshotVisible = isScreenshotSupported(); final boolean captureScreenshotVisible = isScreenshotSupported();
@ -243,7 +244,10 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
return !plot2dVisible; return !plot2dVisible;
} else if ( menuItem == captureScreenshotMenuItem ) { } else if ( menuItem == captureScreenshotMenuItem ) {
return !captureScreenshotVisible; return !captureScreenshotVisible;
} else if ( menuItem == PlotMenu.range ) {
return !plotRangeVisible;
} }
return false; return false;
} }
}); });

View File

@ -145,6 +145,11 @@ public class CalculatorGraph2dView extends View implements GraphView {
return this.graphViewHelper.getPlotFunctions(); return this.graphViewHelper.getPlotFunctions();
} }
@Override
public void onDestroy() {
onPause();
}
@NotNull @NotNull
public Bitmap captureScreenshot() { public Bitmap captureScreenshot() {
final Bitmap result = Bitmap.createBitmap(dimensions.getVWidthPxs(), dimensions.getVHeightPxs(), Bitmap.Config.RGB_565); final Bitmap result = Bitmap.createBitmap(dimensions.getVWidthPxs(), dimensions.getVHeightPxs(), Bitmap.Config.RGB_565);

View File

@ -8,7 +8,6 @@ import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.ZoomButtonsController; import android.widget.ZoomButtonsController;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.App;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11;
@ -18,16 +17,32 @@ import java.util.List;
public class CalculatorGraph3dView extends GLView implements GraphView { public class CalculatorGraph3dView extends GLView implements GraphView {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5; private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5;
private float lastTouchX, lastTouchY; private float lastTouchX, lastTouchY;
private TouchHandler touchHandler; private TouchHandler touchHandler;
private ZoomButtonsController zoomController = new ZoomButtonsController(this); private ZoomButtonsController zoomController = new ZoomButtonsController(this);
private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
private FPS fps = new FPS();
@NotNull private float zoomLevel = 1;
private GLText glText; private float zoomTarget;
private float zoomStep = 0;
private float currentZoom;
@NotNull @NotNull
private List<Graph3d> graphs = new ArrayList<Graph3d>(); private List<Graph3d> graphs = new ArrayList<Graph3d>();
@ -35,6 +50,17 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
@NotNull @NotNull
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance(); private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
@NotNull
private Graph2dDimensions dimensions = new Graph2dDimensions(this);
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
public CalculatorGraph3dView(Context context, AttributeSet attrs) { public CalculatorGraph3dView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init(); init();
@ -54,6 +80,235 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
Matrix.rotateM(matrix1, 0, -75, 1, 0, 0); Matrix.rotateM(matrix1, 0, -75, 1, 0, 0);
} }
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
protected void onSizeChanged(int w, int h, int ow, int oh) {
dimensions.setViewDimensions(w, h);
}
@Override
protected void glDraw() {
if (zoomStep < 0 && zoomLevel > zoomTarget) {
zoomLevel += zoomStep;
} else if (zoomStep > 0 && zoomLevel < zoomTarget) {
zoomLevel += zoomStep;
} else if (zoomStep != 0) {
zoomStep = 0;
zoomLevel = zoomTarget;
dirty = true;
if (!shouldRotate()) {
stopLooping();
}
}
super.glDraw();
}
@Override
public void onDetachedFromWindow() {
zoomController.setVisible(false);
super.onDetachedFromWindow();
}
// ----
private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
private float angleX, angleY;
private boolean dirty;
private static final float DISTANCE = 15f;
void setRotation(float x, float y) {
angleX = x;
angleY = y;
}
boolean shouldRotate() {
final float limit = .5f;
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
}
@Override
public void init(@NotNull PlotViewDef plotViewDef) {
this.graphViewHelper = GraphViewHelper.newInstance(plotViewDef, Collections.<PlotFunction>emptyList());
}
@Override
public void setPlotFunctions(@NotNull List<PlotFunction> plotFunctions) {
for (PlotFunction plotFunction: plotFunctions) {
final int arity = plotFunction.getXyFunction().getArity();
if (arity != 0 && arity != 1 && arity != 2) {
throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!");
}
}
this.graphViewHelper = this.graphViewHelper.copy(plotFunctions);
zoomLevel = 1;
dirty = true;
}
@NotNull
@Override
public List<PlotFunction> getPlotFunctions() {
return this.graphViewHelper.getPlotFunctions();
}
@Override
public void onDestroy() {
onPause();
}
@Override
public void setXRange(float xMin, float xMax) {
dimensions.setXRange(PlotBoundaries.DEFAULT_MIN_NUMBER, PlotBoundaries.DEFAULT_MAX_NUMBER);
zoomLevel = 1;
dirty = true;
}
@Override
public float getXMin() {
return dimensions.getXMin();
}
@Override
public float getXMax() {
return dimensions.getXMax();
}
@Override
public float getYMin() {
return dimensions.getYMin();
}
@Override
public float getYMax() {
return dimensions.getYMax();
}
@Override
public void invalidateGraphs() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void onSurfaceCreated(GL10 gl, int width, int height) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
final int backgroundColor = graphViewHelper.getPlotViewDef().getBackgroundColor();
gl.glClearColor(Color.red(backgroundColor) / 255f, Color.green(backgroundColor) / 255f, Color.blue(backgroundColor) / 255f, Color.alpha(backgroundColor) / 255f);
gl.glShadeModel(useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
gl.glDisable(GL10.GL_LIGHTING);
ensureGraphsSize((GL11) gl);
dirty = true;
angleX = .5f;
angleY = 0;
gl.glViewport(0, 0, width, height);
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
}
@Override
public void onDrawFrame(GL10 gl10) {
GL11 gl = (GL11) gl10;
if (currentZoom != zoomLevel) {
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
}
if (dirty) {
ensureGraphsSize(gl);
final Graph2dDimensions dimensionsCopy = dimensions.copy();
dimensionsCopy.setGWidth(dimensions.getGWidth() * zoomLevel / 4);
for (int i = 0; i < graphViewHelper.getPlotFunctions().size(); i++) {
graphs.get(i).update(gl, graphViewHelper.getPlotFunctions().get(i), dimensionsCopy);
}
dirty = false;
}
/*if (fps.incFrame()) {
Calculator.log("f/s " + fps.getValue());
}*/
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -DISTANCE * zoomLevel);
Matrix.setIdentityM(matrix2, 0);
float ax = Math.abs(angleX);
float ay = Math.abs(angleY);
if (ay * 3 < ax) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
} else if (ax * 3 < ay) {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
if (ax > ay) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
}
}
Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
gl.glMultMatrixf(matrix3, 0);
System.arraycopy(matrix3, 0, matrix1, 0, 16);
for (Graph3d graph : graphs) {
graph.draw(gl);
}
}
private void ensureGraphsSize(@NotNull GL11 gl) {
while (graphViewHelper.getPlotFunctions().size() > graphs.size()) {
graphs.add(new Graph3d(gl, useHighQuality3d));
}
}
private void initFrustum(GL10 gl, float distance) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
float near = distance * (1 / 3f);
float far = distance * 3f;
float dimen = near / 5f;
float h = dimen * height / width;
gl.glFrustumf(-dimen, dimen, -h, h, near, far);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
}
private void printMatrix(float[] m, String name) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < 16; ++i) {
b.append(m[i]).append(' ');
}
//Calculator.log(name + ' ' + b.toString());
}
/*
**********************************************************************
*
* ZOOM
*
**********************************************************************
*/
public void onVisibilityChanged(boolean visible) { public void onVisibilityChanged(boolean visible) {
} }
@ -61,20 +316,21 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
boolean changed = false; boolean changed = false;
if (zoomIn) { if (zoomIn) {
if (canZoomIn(zoomLevel)) { if (canZoomIn(zoomLevel)) {
targetZoom = zoomLevel * .625f; zoomTarget = zoomLevel * .625f;
zoomStep = -zoomLevel / 40; zoomStep = -zoomLevel / 40;
changed = true; changed = true;
} }
} else { } else {
if (canZoomOut(zoomLevel)) { if (canZoomOut(zoomLevel)) {
targetZoom = zoomLevel * 1.6f; zoomTarget = zoomLevel * 1.6f;
zoomStep = zoomLevel / 20; zoomStep = zoomLevel / 20;
changed = true; changed = true;
} }
} }
if (changed) { if (changed) {
zoomController.setZoomInEnabled(canZoomIn(targetZoom)); zoomController.setZoomInEnabled(canZoomIn(zoomTarget));
zoomController.setZoomOutEnabled(canZoomOut(targetZoom)); zoomController.setZoomOutEnabled(canZoomOut(zoomTarget));
if (!shouldRotate()) { if (!shouldRotate()) {
setRotation(0, 0); setRotation(0, 0);
} }
@ -82,22 +338,6 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
} }
} }
@Override
protected void glDraw() {
if ((zoomStep < 0 && zoomLevel > targetZoom) ||
(zoomStep > 0 && zoomLevel < targetZoom)) {
zoomLevel += zoomStep;
} else if (zoomStep != 0) {
zoomStep = 0;
zoomLevel = targetZoom;
isDirty = true;
if (!shouldRotate()) {
stopLooping();
}
}
super.glDraw();
}
private boolean canZoomIn(float zoom) { private boolean canZoomIn(float zoom) {
return true; return true;
} }
@ -106,11 +346,13 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
return true; return true;
} }
@Override /*
public void onDetachedFromWindow() { **********************************************************************
zoomController.setVisible(false); *
super.onDetachedFromWindow(); * TOUCH
} *
**********************************************************************
*/
public void onTouchDown(float x, float y) { public void onTouchDown(float x, float y) {
zoomController.setVisible(true); zoomController.setVisible(true);
@ -151,195 +393,4 @@ public class CalculatorGraph3dView extends GLView implements GraphView {
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
return touchHandler != null ? touchHandler.handleTouchEvent(event) : super.onTouchEvent(event); return touchHandler != null ? touchHandler.handleTouchEvent(event) : super.onTouchEvent(event);
} }}
// ----
private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
private float angleX, angleY;
private boolean isDirty;
private static final float DISTANCE = 15f;
void setRotation(float x, float y) {
angleX = x;
angleY = y;
}
boolean shouldRotate() {
final float limit = .5f;
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
}
@Override
public void init(@NotNull PlotViewDef plotViewDef) {
this.graphViewHelper = GraphViewHelper.newInstance(plotViewDef, Collections.<PlotFunction>emptyList());
}
@Override
public void setPlotFunctions(@NotNull List<PlotFunction> plotFunctions) {
for (PlotFunction plotFunction: plotFunctions) {
final int arity = plotFunction.getXyFunction().getArity();
if (arity != 0 && arity != 1 && arity != 2) {
throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!");
}
}
this.graphViewHelper = this.graphViewHelper.copy(plotFunctions);
zoomLevel = 1;
isDirty = true;
}
@NotNull
@Override
public List<PlotFunction> getPlotFunctions() {
return this.graphViewHelper.getPlotFunctions();
}
@Override
public void setXRange(float xMin, float xMax) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public float getXMin() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public float getXMax() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public float getYMin() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public float getYMax() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void invalidateGraphs() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void onSurfaceCreated(GL10 gl, int width, int height) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
final int backgroundColor = graphViewHelper.getPlotViewDef().getBackgroundColor();
gl.glClearColor(Color.red(backgroundColor) / 255f, Color.green(backgroundColor) / 255f, Color.blue(backgroundColor) / 255f, Color.alpha(backgroundColor) / 255f);
gl.glShadeModel(useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
gl.glDisable(GL10.GL_LIGHTING);
ensureGraphsSize((GL11) gl);
isDirty = true;
angleX = .5f;
angleY = 0;
gl.glViewport(0, 0, width, height);
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
glText = new GLText( gl, App.getInstance().getApplication().getAssets() );
glText.load("Roboto-Regular.ttf", 32, 2, 2);
}
@Override
public void onDrawFrame(GL10 gl10) {
GL11 gl = (GL11) gl10;
if (currentZoom != zoomLevel) {
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
}
if (isDirty) {
ensureGraphsSize(gl);
for (int i = 0; i < graphViewHelper.getPlotFunctions().size(); i++) {
graphs.get(i).update(gl, graphViewHelper.getPlotFunctions().get(i), zoomLevel);
}
isDirty = false;
}
/*if (fps.incFrame()) {
Calculator.log("f/s " + fps.getValue());
}*/
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -DISTANCE * zoomLevel);
Matrix.setIdentityM(matrix2, 0);
float ax = Math.abs(angleX);
float ay = Math.abs(angleY);
if (ay * 3 < ax) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
} else if (ax * 3 < ay) {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
if (ax > ay) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
}
}
Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
gl.glMultMatrixf(matrix3, 0);
System.arraycopy(matrix3, 0, matrix1, 0, 16);
for (Graph3d graph : graphs) {
graph.draw(gl);
}
//updateText(gl, glText);
}
public void drawText(@NotNull GLText glText) {
glText.begin(1.0f, 1.0f, 1.0f, 1.0f);
glText.draw( "Test!", 0, 0 );
glText.end();
}
private void updateText(@NotNull GL11 gl, @NotNull GLText glText) {
gl.glEnable( GL10.GL_TEXTURE_2D );
gl.glEnable( GL10.GL_BLEND );
gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
drawText(glText);
gl.glDisable( GL10.GL_BLEND );
gl.glDisable( GL10.GL_TEXTURE_2D );
}
private void ensureGraphsSize(@NotNull GL11 gl) {
while (graphViewHelper.getPlotFunctions().size() > graphs.size()) {
graphs.add(new Graph3d(gl, useHighQuality3d));
}
}
private void initFrustum(GL10 gl, float distance) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
float near = distance * (1 / 3f);
float far = distance * 3f;
float dimen = near / 5f;
float h = dimen * height / width;
gl.glFrustumf(-dimen, dimen, -h, h, near, far);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
}
private void printMatrix(float[] m, String name) {
StringBuffer b = new StringBuffer();
for (int i = 0; i < 16; ++i) {
b.append(m[i]).append(' ');
}
//Calculator.log(name + ' ' + b.toString());
}
}

View File

@ -21,7 +21,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
@Nullable @Nullable
@Override @Override
protected PlotBoundaries getPlotBoundaries() { protected PlotBoundaries getPlotBoundaries() {
if ( graphView != null ) { if ( graphView instanceof CalculatorGraph2dView ) {
return PlotBoundaries.newInstance(graphView.getXMin(), graphView.getXMax(), graphView.getYMin(), graphView.getYMax()); return PlotBoundaries.newInstance(graphView.getXMin(), graphView.getXMax(), graphView.getYMin(), graphView.getYMax());
} else { } else {
return null; return null;
@ -35,6 +35,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout); final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
if (graphView instanceof View) { if (graphView instanceof View) {
graphView.onDestroy();
graphContainer.removeView((View) graphView); graphContainer.removeView((View) graphView);
} }
@ -44,8 +45,6 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
graphView = new CalculatorGraph2dView(getActivity()); graphView = new CalculatorGraph2dView(getActivity());
} }
// todo serso: investigate (after switching from 3d to 2d - blank screen)
graphView.init(PlotViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor())); graphView.init(PlotViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
graphView.setXRange(plotData.getBoundaries().getXMin(), plotData.getBoundaries().getXMax()); graphView.setXRange(plotData.getBoundaries().getXMin(), plotData.getBoundaries().getXMax());
graphView.setPlotFunctions(plotData.getFunctions()); graphView.setPlotFunctions(plotData.getFunctions());
@ -104,4 +103,14 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
super.onPause(); super.onPause();
} }
@Override
public void onDestroyView() {
if (this.graphView != null) {
this.graphView.onDestroy();
}
super.onDestroyView();
}
} }

View File

@ -194,4 +194,17 @@ public class Graph2dDimensions {
this.x0 += dx; this.x0 += dx;
this.y0 += dy; this.y0 += dy;
} }
@NotNull
public Graph2dDimensions copy() {
final Graph2dDimensions copy = new Graph2dDimensions(this.graphView);
copy.vWidthPxs = this.vWidthPxs;
copy.vHeightPxs = this.vHeightPxs;
copy.x0 = this.x0;
copy.y0 = this.y0;
copy.gWidth = this.gWidth;
return copy;
}
} }

View File

@ -91,20 +91,18 @@ class Graph3d {
return bb; return bb;
} }
public void update(@NotNull GL11 gl, @NotNull PlotFunction fpd, float zoom) { public void update(@NotNull GL11 gl, @NotNull PlotFunction fpd, @NotNull Graph2dDimensions dimensions) {
final XyFunction function = fpd.getXyFunction(); final XyFunction function = fpd.getXyFunction();
final PlotLineDef lineDef = fpd.getPlotLineDef(); final PlotLineDef lineDef = fpd.getPlotLineDef();
final int NTICK = useHighQuality3d ? 5 : 0; final int NTICK = useHighQuality3d ? 5 : 0;
final float size = 4 * zoom;
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo); //Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
polygonsⁿ = n * n + 6 + 8 + NTICK * 6; polygonsⁿ = n * n + 6 + 8 + NTICK * 6;
// triangle polygon => 3 vertices per polygon // triangle polygon => 3 vertices per polygon
final float vertices[] = new float[polygonsⁿ * VERTICES_COUNT]; final float vertices[] = new float[polygonsⁿ * VERTICES_COUNT];
float maxAbsZ = fillFunctionPolygonVertices(function, size, vertices); float maxAbsZ = fillFunctionPolygonVertices(function, dimensions, vertices);
final byte[] colors = prepareFunctionPolygonColors(lineDef, vertices, maxAbsZ); final byte[] colors = prepareFunctionPolygonColors(lineDef, vertices, maxAbsZ);
@ -229,19 +227,20 @@ class Graph3d {
} }
} }
private float fillFunctionPolygonVertices(XyFunction function, float size, float[] vertices) { private float fillFunctionPolygonVertices(XyFunction function, @NotNull Graph2dDimensions dimensions, float[] vertices) {
final int arity = function.getArity(); final int arity = function.getArity();
final float minX = -size; final float xMin = dimensions.getXMin();
final float maxX = size; final float xMax = dimensions.getXMax();
final float minY = -size;
final float maxY = size;
float Δx = (maxX - minX) / (n - 1); final float yMin = dimensions.getXMin();
float Δy = (maxY - minY) / (n - 1); final float yMax = dimensions.getXMax();
float y = minY; float Δx = (xMax - xMin) / (n - 1);
float x = minX - Δx; float Δy = (yMax - yMin) / (n - 1);
float y = yMin;
float x = xMin - Δx;
float maxAbsZ = 0; float maxAbsZ = 0;

View File

@ -15,6 +15,7 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa
@NotNull @NotNull
public List<PlotFunction> getPlotFunctions(); public List<PlotFunction> getPlotFunctions();
public void onDestroy();
public void onPause(); public void onPause();
public void onResume(); public void onResume();

View File

@ -11,9 +11,9 @@ import java.io.Serializable;
*/ */
public final class PlotBoundaries implements Serializable { public final class PlotBoundaries implements Serializable {
private static final float DEFAULT_MIN_NUMBER = -10f; public static final float DEFAULT_MIN_NUMBER = -10f;
private static final float DEFAULT_MAX_NUMBER = 10f; public static final float DEFAULT_MAX_NUMBER = 10f;
private float xMin; private float xMin;