From cc5d74b54b08930966a5e47967493184eae54475 Mon Sep 17 00:00:00 2001 From: Sergey Solovyev Date: Sat, 19 Jan 2013 23:59:14 +0400 Subject: [PATCH] new plotter --- .../calculator/CalculatorActivity.java | 33 +- .../calculator/CalculatorActivityHelper.java | 2 + .../CalculatorActivityHelperImpl.java | 12 + .../CalculatorActivityLauncher.java | 8 - .../plot/AbstractCalculatorPlotFragment.java | 10 +- .../plot/CalculatorGraph2dView.java | 5 + .../plot/CalculatorGraph3dView.java | 495 ++++++++++-------- .../plot/CalculatorPlotFragment.java | 15 +- .../calculator/plot/Graph2dDimensions.java | 13 + .../android/calculator/plot/Graph3d.java | 25 +- .../android/calculator/plot/GraphView.java | 1 + .../calculator/plot/PlotBoundaries.java | 4 +- 12 files changed, 370 insertions(+), 253 deletions(-) diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index d032b5df..c28a0870 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -19,6 +19,7 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.TextView; +import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockFragmentActivity; import org.jetbrains.annotations.NotNull; 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.text.StringUtils; -public class CalculatorActivity extends SherlockFragmentActivity implements SharedPreferences.OnSharedPreferenceChangeListener { +public class CalculatorActivity extends SherlockFragmentActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener { @NotNull public static final String TAG = CalculatorActivity.class.getSimpleName(); @@ -57,7 +58,7 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar super.onCreate(savedInstanceState); 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.saved_history, 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 private AndroidCalculator getCalculator() { return ((AndroidCalculator) Locator.getInstance().getCalculator()); @@ -321,4 +326,28 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar 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; + } + } } \ No newline at end of file diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelper.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelper.java index e1fd8090..ae289f13 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelper.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelper.java @@ -61,4 +61,6 @@ public interface CalculatorActivityHelper { void processButtons(@NotNull Activity activity, @NotNull View root); void logError(@NotNull String message); + + void selectTab(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType); } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelperImpl.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelperImpl.java index b9015a17..81222854 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelperImpl.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityHelperImpl.java @@ -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 public int getLayoutId() { return layoutId; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java index a368efa1..9850959f 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java @@ -233,14 +233,6 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener } }); break; - case plot_graph: - App.getInstance().getUiThreadExecutor().execute(new Runnable() { - @Override - public void run() { - plotGraph(context); - } - }); - break; case show_evaluation_error: final String errorMessage = (String) data; if (errorMessage != null) { diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java index 606de13c..111bf3a8 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java @@ -136,14 +136,14 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment Threads.tryRunOnUiThread(activity, new Runnable() { @Override public void run() { - activity.invalidateOptionsMenu(); - createChart(plotData); final View view = getView(); if (view != null) { createGraphicalView(view, plotData); } + + activity.invalidateOptionsMenu(); } }); } @@ -231,6 +231,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment }; menuItems.add(captureScreenshotMenuItem); + final boolean plotRangeVisible = !plotData.isPlot3d(); final boolean plot3dVisible = !plotData.isPlot3d() && is3dPlotSupported(); final boolean plot2dVisible = plotData.isPlot3d() && Locator.getInstance().getPlotter().is2dPlotPossible(); final boolean captureScreenshotVisible = isScreenshotSupported(); @@ -243,7 +244,10 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment return !plot2dVisible; } else if ( menuItem == captureScreenshotMenuItem ) { return !captureScreenshotVisible; - } + } else if ( menuItem == PlotMenu.range ) { + return !plotRangeVisible; + } + return false; } }); diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java index c0e98ac9..5da8c84e 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph2dView.java @@ -145,6 +145,11 @@ public class CalculatorGraph2dView extends View implements GraphView { return this.graphViewHelper.getPlotFunctions(); } + @Override + public void onDestroy() { + onPause(); + } + @NotNull public Bitmap captureScreenshot() { final Bitmap result = Bitmap.createBitmap(dimensions.getVWidthPxs(), dimensions.getVHeightPxs(), Bitmap.Config.RGB_565); diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph3dView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph3dView.java index b29b718a..fd056841 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph3dView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorGraph3dView.java @@ -8,7 +8,6 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ZoomButtonsController; import org.jetbrains.annotations.NotNull; -import org.solovyev.android.App; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; @@ -18,16 +17,32 @@ import java.util.List; public class CalculatorGraph3dView extends GLView implements GraphView { + /* + ********************************************************************** + * + * CONSTANTS + * + ********************************************************************** + */ + + /* + ********************************************************************** + * + * FIELDS + * + ********************************************************************** + */ + private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5; private float lastTouchX, lastTouchY; private TouchHandler touchHandler; private ZoomButtonsController zoomController = new ZoomButtonsController(this); - private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom; - private FPS fps = new FPS(); - @NotNull - private GLText glText; + private float zoomLevel = 1; + private float zoomTarget; + private float zoomStep = 0; + private float currentZoom; @NotNull private List graphs = new ArrayList(); @@ -35,6 +50,17 @@ public class CalculatorGraph3dView extends GLView implements GraphView { @NotNull private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance(); + @NotNull + private Graph2dDimensions dimensions = new Graph2dDimensions(this); + + /* + ********************************************************************** + * + * CONSTRUCTORS + * + ********************************************************************** + */ + public CalculatorGraph3dView(Context context, AttributeSet attrs) { super(context, attrs); init(); @@ -54,6 +80,235 @@ public class CalculatorGraph3dView extends GLView implements GraphView { 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.emptyList()); + } + + @Override + public void setPlotFunctions(@NotNull List 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 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) { } @@ -61,20 +316,21 @@ public class CalculatorGraph3dView extends GLView implements GraphView { boolean changed = false; if (zoomIn) { if (canZoomIn(zoomLevel)) { - targetZoom = zoomLevel * .625f; + zoomTarget = zoomLevel * .625f; zoomStep = -zoomLevel / 40; changed = true; } } else { if (canZoomOut(zoomLevel)) { - targetZoom = zoomLevel * 1.6f; + zoomTarget = zoomLevel * 1.6f; zoomStep = zoomLevel / 20; changed = true; } } + if (changed) { - zoomController.setZoomInEnabled(canZoomIn(targetZoom)); - zoomController.setZoomOutEnabled(canZoomOut(targetZoom)); + zoomController.setZoomInEnabled(canZoomIn(zoomTarget)); + zoomController.setZoomOutEnabled(canZoomOut(zoomTarget)); if (!shouldRotate()) { 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) { return true; } @@ -106,11 +346,13 @@ public class CalculatorGraph3dView extends GLView implements GraphView { return true; } - @Override - public void onDetachedFromWindow() { - zoomController.setVisible(false); - super.onDetachedFromWindow(); - } + /* + ********************************************************************** + * + * TOUCH + * + ********************************************************************** + */ public void onTouchDown(float x, float y) { zoomController.setVisible(true); @@ -151,195 +393,4 @@ public class CalculatorGraph3dView extends GLView implements GraphView { @Override public boolean onTouchEvent(MotionEvent 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.emptyList()); - } - - @Override - public void setPlotFunctions(@NotNull List 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 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()); - } -} + }} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java index 6a5143e3..2bcd05cf 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotFragment.java @@ -21,7 +21,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { @Nullable @Override protected PlotBoundaries getPlotBoundaries() { - if ( graphView != null ) { + if ( graphView instanceof CalculatorGraph2dView ) { return PlotBoundaries.newInstance(graphView.getXMin(), graphView.getXMax(), graphView.getYMin(), graphView.getYMax()); } else { return null; @@ -35,6 +35,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout); if (graphView instanceof View) { + graphView.onDestroy(); graphContainer.removeView((View) graphView); } @@ -44,8 +45,6 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { 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.setXRange(plotData.getBoundaries().getXMin(), plotData.getBoundaries().getXMax()); graphView.setPlotFunctions(plotData.getFunctions()); @@ -104,4 +103,14 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { super.onPause(); } + + @Override + public void onDestroyView() { + if (this.graphView != null) { + this.graphView.onDestroy(); + } + + super.onDestroyView(); + } + } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph2dDimensions.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph2dDimensions.java index b0e41999..15c342bd 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph2dDimensions.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph2dDimensions.java @@ -194,4 +194,17 @@ public class Graph2dDimensions { this.x0 += dx; 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; + } } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java index 2f2ae959..e1555970 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/Graph3d.java @@ -91,20 +91,18 @@ class Graph3d { 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 PlotLineDef lineDef = fpd.getPlotLineDef(); final int NTICK = useHighQuality3d ? 5 : 0; - final float size = 4 * zoom; - //Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo); polygonsⁿ = n * n + 6 + 8 + NTICK * 6; // triangle polygon => 3 vertices per polygon 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); @@ -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 float minX = -size; - final float maxX = size; - final float minY = -size; - final float maxY = size; + final float xMin = dimensions.getXMin(); + final float xMax = dimensions.getXMax(); - float Δx = (maxX - minX) / (n - 1); - float Δy = (maxY - minY) / (n - 1); + final float yMin = dimensions.getXMin(); + final float yMax = dimensions.getXMax(); - float y = minY; - float x = minX - Δx; + float Δx = (xMax - xMin) / (n - 1); + float Δy = (yMax - yMin) / (n - 1); + + float y = yMin; + float x = xMin - Δx; float maxAbsZ = 0; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java index 8e507626..e1d04c9c 100755 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/GraphView.java @@ -15,6 +15,7 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa @NotNull public List getPlotFunctions(); + public void onDestroy(); public void onPause(); public void onResume(); diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/PlotBoundaries.java b/core/src/main/java/org/solovyev/android/calculator/plot/PlotBoundaries.java index 42318930..88dd077b 100644 --- a/core/src/main/java/org/solovyev/android/calculator/plot/PlotBoundaries.java +++ b/core/src/main/java/org/solovyev/android/calculator/plot/PlotBoundaries.java @@ -11,9 +11,9 @@ import java.io.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;