new plotter
This commit is contained in:
parent
3f76f61c4b
commit
cc5d74b54b
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user