From 6a4d990d9c6bed58dee7155373f529d4da983be6 Mon Sep 17 00:00:00 2001 From: Sergey Solovyev Date: Sun, 16 Jun 2013 14:43:34 +0400 Subject: [PATCH] graph improvements --- .../plot/AbstractCalculatorPlotFragment.java | 31 +++---- .../plot/CalculatorGraph2dView.java | 82 ++++++++++++++++--- .../plot/CalculatorGraph3dView.java | 5 ++ .../plot/CalculatorPlotFragment.java | 4 +- .../android/calculator/plot/GraphView.java | 14 +--- .../plot/CalculatorPlotterImpl.java | 8 +- .../android/calculator/plot/PlotData.java | 14 +++- 7 files changed, 114 insertions(+), 44 deletions(-) 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 b778462f..4c9ec1a6 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 @@ -15,12 +15,9 @@ import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.solovyev.android.Android; import org.solovyev.android.Threads; import org.solovyev.android.calculator.*; -import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.menu.AMenuItem; import org.solovyev.android.menu.ActivityMenu; import org.solovyev.android.menu.IdentifiableMenuItem; @@ -29,6 +26,8 @@ import org.solovyev.android.sherlock.menu.SherlockMenuHelper; import org.solovyev.common.JPredicate; import org.solovyev.common.msg.MessageType; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -38,6 +37,8 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences; + /** * User: serso * Date: 12/30/12 @@ -66,7 +67,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment private int bgColor; @Nonnull - private PlotData plotData = new PlotData(Collections.emptyList(), false, PlotBoundaries.newDefaultInstance()); + private PlotData plotData = new PlotData(Collections.emptyList(), false, true, PlotBoundaries.newDefaultInstance()); @Nonnull private ActivityMenu fragmentMenu; @@ -107,15 +108,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment @Nullable protected abstract PlotBoundaries getPlotBoundaries(); - @Override - public void onPause() { - PreferenceManager.getDefaultSharedPreferences(this.getActivity()).unregisterOnSharedPreferenceChangeListener(this); - - savePlotBoundaries(); - - super.onPause(); - } - @Override public void onResume() { super.onResume(); @@ -126,9 +118,18 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment updateChart(plotData, getSherlockActivity()); } + @Override + public void onPause() { + PreferenceManager.getDefaultSharedPreferences(this.getActivity()).unregisterOnSharedPreferenceChangeListener(this); + + savePlotBoundaries(); + + super.onPause(); + } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (AndroidCalculatorEngine.Preferences.angleUnit.getKey().equals(key)) { + if (Preferences.angleUnit.getKey().equals(key)) { updateChart(this.plotData, getSherlockActivity()); } } @@ -139,6 +140,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment case plot_data_changed: final CalculatorEventHolder.Result result = this.lastEventHolder.apply(calculatorEventData); if (result.isNewAfter()) { + assert data != null; onNewPlotData((PlotData) data); } break; @@ -164,6 +166,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment createGraphicalView(view, plotData); } + assert activity != null; activity.invalidateOptionsMenu(); } }); 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 e6cfad79..698e2c5c 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 @@ -8,9 +8,9 @@ import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; import android.widget.ZoomButtonsController; -import javax.annotation.Nonnull; import org.solovyev.common.math.Point2d; +import javax.annotation.Nonnull; import java.text.DecimalFormat; import java.util.Collections; import java.util.List; @@ -18,17 +18,19 @@ import java.util.List; public class CalculatorGraph2dView extends View implements GraphView { /* - ********************************************************************** - * - * CONSTANTS - * - ********************************************************************** - */ + ********************************************************************** + * + * CONSTANTS + * + ********************************************************************** + */ private static final int NO_TOUCH = -1; private static final float TICKS_COUNT = 15; public static final int TICK_SIZE_PXS = 3; + private static final float Y_TO_X_ADJUST_SCALE = 2f; + private static final DecimalFormat tickFormat = new DecimalFormat("##0.#####E0"); private static final int MAX_TICK_DIGITS = 4; private static final String[] TICK_FORMATS = new String[MAX_TICK_DIGITS]; @@ -38,6 +40,7 @@ public class CalculatorGraph2dView extends View implements GraphView { TICK_FORMATS[i] = "%." + i + "f"; } } + /* ********************************************************************** * @@ -83,7 +86,9 @@ public class CalculatorGraph2dView extends View implements GraphView { @Nonnull private final GraphCalculator graphCalculator = new GraphCalculatorImpl(); - private boolean mDrawn = false; + private boolean drawn = false; + + private boolean adjustYAxis = false; /* ********************************************************************** @@ -162,12 +167,17 @@ public class CalculatorGraph2dView extends View implements GraphView { public void invalidateGraphs() { graphsData.clear(); - if (mDrawn) { - mDrawn = false; + if (drawn) { + drawn = false; invalidate(); } } + @Override + public void setAdjustYAxis(boolean adjustYAxis) { + this.adjustYAxis = adjustYAxis; + } + public void onResume() { } @@ -228,7 +238,12 @@ public class CalculatorGraph2dView extends View implements GraphView { } private void drawGraph(@Nonnull Canvas canvas) { - mDrawn = true; + drawn = true; + + if(adjustYAxis) { + adjustYAxis(); + adjustYAxis = false; + } final float graphWidth = dimensions.getGWidth(); final float graphHeight = dimensions.getGHeight(); @@ -300,6 +315,51 @@ public class CalculatorGraph2dView extends View implements GraphView { graphsData.setLastXMax(xMax); } + private void adjustYAxis() { + final float xMin = dimensions.getXMin(); + final float xMax = dimensions.getXMax(xMin); + + float yMax = -Float.MAX_VALUE; + float yMin = Float.MAX_VALUE; + + graphsData.checkBoundaries(Float.MAX_VALUE, -Float.MAX_VALUE, Float.MAX_VALUE); + + final List plotFunctions = graphViewHelper.getPlotFunctions(); + + for (int i = 0; i < plotFunctions.size(); i++) { + final PlotFunction plotFunction = plotFunctions.get(i); + final GraphData graph = graphsData.get(i); + + graphCalculator.computeGraph(plotFunction.getXyFunction(), xMin, xMax, graph, graphsData, dimensions); + + final float[] ys = graph.getYs(); + for (int j = 0; j < graph.getSize(); j++) { + final float y = ys[j]; + if (!Float.isNaN(y)) { + yMax = Math.max(yMax, y); + yMin = Math.min(yMin, y); + } + } + } + + final float xDist = xMax - xMin; + + yMax = Math.min(yMax, xDist); + yMin = Math.max(yMin, -xDist); + + if (yMax - yMin > 0.00000001) { + final float yDist = yMax - yMin; + float maxYDist = Y_TO_X_ADJUST_SCALE * xDist; + if (yDist > maxYDist) { + // usually functions are symmetrical => just make a symmetry + yMax = yMax - yDist / 2 + maxYDist / 2; + yMin = yMin + yDist / 2 - maxYDist / 2; + } + + dimensions.setYRange(yMin, yMax); + } + } + @Nonnull private TickDigits drawGridAndAxis(@Nonnull Canvas canvas) { final TickDigits result = new TickDigits(); 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 ba67da98..c253b47d 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 @@ -203,6 +203,11 @@ public class CalculatorGraph3dView extends GLView implements GraphView { //To change body of implemented methods use File | Settings | File Templates. } + @Override + public void setAdjustYAxis(boolean adjustYAxis) { + // not supported + } + @Override public void onSurfaceCreated(GL10 gl, int width, int height) { gl.glDisable(GL10.GL_DITHER); 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 42fed508..ac12e225 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 @@ -4,9 +4,10 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.view.View; import android.view.ViewGroup; +import org.solovyev.android.calculator.R; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.solovyev.android.calculator.R; /** * User: serso @@ -50,6 +51,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment { final PlotBoundaries boundaries = plotData.getBoundaries(); graphView.setXRange(boundaries.getXMin(), boundaries.getXMax()); graphView.setYRange(boundaries.getYMin(), boundaries.getYMax()); + graphView.setAdjustYAxis(plotData.isAdjustYAxis()); graphView.setPlotFunctions(plotData.getFunctions()); 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 aa6fd36a..e95e2e97 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 @@ -38,17 +38,5 @@ public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHa void invalidateGraphs(); -/* void increaseDensity(); - void decreaseDensity();*/ - - /* - ********************************************************************** - * - * CUSTOMIZATION - * - ********************************************************************** - */ - -/* void setBgColor(int color); - void setAxisColor(int color);*/ + void setAdjustYAxis(boolean adjustYAxis); } diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java b/core/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java index 137f9f6a..95e5f18c 100644 --- a/core/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java +++ b/core/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java @@ -31,6 +31,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { private final PlotResourceManager resourceManager = new MapPlotResourceManager(); private boolean plot3d = false; + private boolean adjustYAxis = true; private boolean plotImag = false; @@ -40,7 +41,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance(); @Nonnull - private PlotData plotData = new PlotData(Collections.emptyList(), plot3d, plotBoundaries); + private PlotData plotData = new PlotData(Collections.emptyList(), plot3d, true, plotBoundaries); public CalculatorPlotterImpl(@Nonnull Calculator calculator) { this.calculator = calculator; @@ -308,6 +309,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { if (functions.isEmpty()) { // no functions => new plot => default boundaries this.plotBoundaries = PlotBoundaries.newDefaultInstance(); + this.adjustYAxis = true; } arity = maxArity; @@ -378,7 +380,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { } private void updatePlotData() { - plotData = new PlotData(getVisibleFunctions(), plot3d, plotBoundaries); + plotData = new PlotData(getVisibleFunctions(), plot3d, adjustYAxis, plotBoundaries); } @Override @@ -395,6 +397,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { public void savePlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) { if (!this.plotBoundaries.equals(plotBoundaries)) { this.plotBoundaries = plotBoundaries; + this.adjustYAxis = false; updatePlotData(); } } @@ -403,6 +406,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter { public void setPlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) { if (!this.plotBoundaries.equals(plotBoundaries)) { this.plotBoundaries = plotBoundaries; + this.adjustYAxis = false; firePlotDataChangedEvent(); } } diff --git a/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java b/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java index 1ca69dde..e860d19f 100644 --- a/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java +++ b/core/src/main/java/org/solovyev/android/calculator/plot/PlotData.java @@ -12,18 +12,22 @@ import java.util.List; public class PlotData { @Nonnull - private List functions; + private final List functions; - private boolean plot3d; + private final boolean plot3d; + + private final boolean adjustYAxis; @Nonnull - private PlotBoundaries boundaries; + private final PlotBoundaries boundaries; public PlotData(@Nonnull List functions, boolean plot3d, + boolean adjustYAxis, @Nonnull PlotBoundaries boundaries) { this.functions = functions; this.plot3d = plot3d; + this.adjustYAxis = adjustYAxis; this.boundaries = boundaries; } @@ -40,4 +44,8 @@ public class PlotData { public PlotBoundaries getBoundaries() { return boundaries; } + + public boolean isAdjustYAxis() { + return adjustYAxis; + } }