From f7b66673a5abcf4852ef512e553f8be04ea3e1f0 Mon Sep 17 00:00:00 2001 From: serso Date: Sun, 28 Feb 2016 13:08:10 +0100 Subject: [PATCH] Plotter --- .../android/calculator/ActivityLauncher.java | 94 ++-- .../calculator/CalculatorApplication.java | 18 +- .../android/calculator/CalculatorLocator.java | 7 +- .../android/calculator/CalculatorUtils.java | 23 - .../solovyev/android/calculator/Display.java | 2 - .../android/calculator/DisplayFragment.java | 24 +- .../solovyev/android/calculator/Locator.java | 14 +- .../solovyev/android/calculator/Notifier.java | 31 +- .../calculator/keyboard/BaseKeyboardUi.java | 28 +- .../keyboard/PartialKeyboardUi.java | 3 +- .../plot/CalculatorPlotterImpl.java | 442 ------------------ .../calculator/plot/PlotFunctionListItem.java | 152 ------ .../calculator/AbstractCalculatorTest.java | 3 +- .../calculator/CalculatorTestUtils.java | 5 +- jscl/src/main/java/jscl/math/Generic.java | 29 +- .../jscl/math/function/CustomFunction.java | 4 +- 16 files changed, 131 insertions(+), 748 deletions(-) delete mode 100644 app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionListItem.java diff --git a/app/src/main/java/org/solovyev/android/calculator/ActivityLauncher.java b/app/src/main/java/org/solovyev/android/calculator/ActivityLauncher.java index 784812af..23e87af2 100644 --- a/app/src/main/java/org/solovyev/android/calculator/ActivityLauncher.java +++ b/app/src/main/java/org/solovyev/android/calculator/ActivityLauncher.java @@ -28,7 +28,11 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.annotation.NonNull; - +import android.text.TextUtils; +import dagger.Lazy; +import jscl.math.Generic; +import jscl.math.function.Constant; +import jscl.math.function.CustomFunction; import org.solovyev.android.Activities; import org.solovyev.android.Check; import org.solovyev.android.calculator.about.AboutActivity; @@ -38,31 +42,40 @@ import org.solovyev.android.calculator.functions.FunctionsActivity; import org.solovyev.android.calculator.history.HistoryActivity; import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity; import org.solovyev.android.calculator.operators.OperatorsActivity; -import org.solovyev.android.calculator.plot.CalculatorPlotter; +import org.solovyev.android.calculator.plot.ExpressionFunction; import org.solovyev.android.calculator.plot.PlotActivity; import org.solovyev.android.calculator.preferences.PreferencesActivity; import org.solovyev.android.calculator.variables.CppVariable; import org.solovyev.android.calculator.variables.EditVariableFragment; import org.solovyev.android.calculator.variables.VariablesActivity; import org.solovyev.android.calculator.variables.VariablesFragment; +import org.solovyev.android.plotter.Plotter; import org.solovyev.common.msg.MessageType; import org.solovyev.common.text.Strings; -import jscl.math.Generic; -import jscl.math.function.Constant; - -import java.util.Set; - import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; @Singleton public final class ActivityLauncher implements CalculatorEventListener { @Inject Application application; + @Inject + Lazy plotter; + @Inject + Lazy errorReporter; + @Inject + Lazy display; + @Inject + Lazy variablesRegistry; + @Inject + Notifier notifier; @Nullable private CalculatorActivity activity; @@ -109,7 +122,7 @@ public final class ActivityLauncher implements CalculatorEventListener { final CppFunction.Builder builder = CppFunction.builder("", functionBody); final Generic generic = viewState.getResult(); if (generic != null) { - final Set constants = CalculatorUtils.getNotSystemConstants(generic); + final Set constants = generic.getUndefinedConstants(null); for (Constant constant : constants) { builder.withParameter(constant.getName()); } @@ -128,26 +141,13 @@ public final class ActivityLauncher implements CalculatorEventListener { return ((CalculatorApplication) App.getApplication()).notifier; } - public static void tryPlot() { - final CalculatorPlotter plotter = Locator.getInstance().getPlotter(); - final Display display = App.getDisplay(); - final DisplayState viewState = display.getState(); - - if (viewState.valid) { - final String functionValue = viewState.text; - final Generic expression = viewState.getResult(); - if (!Strings.isEmpty(functionValue) && expression != null) { - if (plotter.isPlotPossibleFor(expression)) { - plotter.plot(expression); - } else { - getNotifier().showMessage(R.string.cpp_plot_too_many_variables, MessageType.error); - } - } else { - getNotifier().showMessage(R.string.cpp_plot_empty_function_error, MessageType.error); - } - } else { + public void plotDisplayedExpression() { + final DisplayState state = display.get().getState(); + if (!state.valid) { getNotifier().showMessage(R.string.not_valid_result, MessageType.error); + return; } + plot(state.getResult()); } public void showHistory() { @@ -161,7 +161,7 @@ public final class ActivityLauncher implements CalculatorEventListener { public void showWidgetSettings() { final Context context = getContext(); show(context, PreferencesActivity.makeIntent(context, R.xml.preferences_widget, - R.string.prefs_widget_title)); + R.string.prefs_widget_title)); } public void showOperators() { @@ -258,4 +258,44 @@ public final class ActivityLauncher implements CalculatorEventListener { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(intent); } + + void plot(@Nullable Generic expression) { + if (expression == null) { + notifier.showMessage(R.string.cpp_plot_empty_function_error); + return; + } + final String content = expression.toString(); + if (TextUtils.isEmpty(content)) { + notifier.showMessage(R.string.cpp_plot_empty_function_error); + return; + } + final List parameters = new ArrayList<>(); + for (Constant parameter : expression.getUndefinedConstants(variablesRegistry.get())) { + parameters.add(parameter.getName()); + } + if (parameters.size() > 2) { + notifier.showMessage(R.string.cpp_plot_too_many_variables); + return; + } + + try { + final CustomFunction f = new CustomFunction.Builder().setName("").setParameterNames(parameters).setContent(content).create(); + final ExpressionFunction ef = new ExpressionFunction(f, false); + plotter.get().add(ef); + showPlotter(); + } catch (RuntimeException e) { + errorReporter.get().onException(e); + notifier.showMessage(e.getLocalizedMessage()); + } + } + + public boolean canPlot(@Nullable Generic expression) { + if (expression == null || TextUtils.isEmpty(expression.toString())) { + return false; + } + if (expression.getUndefinedConstants(variablesRegistry.get()).size() > 2) { + return false; + } + return true; + } } diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java index 6cee763a..7a9c09ce 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java @@ -27,9 +27,8 @@ import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; import android.util.TimingLogger; - import com.squareup.otto.Bus; - +import jscl.MathEngine; import org.acra.ACRA; import org.acra.ACRAConfiguration; import org.acra.sender.HttpSender; @@ -38,18 +37,13 @@ import org.solovyev.android.calculator.floating.FloatingCalculatorActivity; import org.solovyev.android.calculator.history.History; import org.solovyev.android.calculator.language.Language; import org.solovyev.android.calculator.language.Languages; -import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter; -import org.solovyev.android.calculator.plot.CalculatorPlotterImpl; import org.solovyev.common.msg.MessageType; -import jscl.MathEngine; - -import java.util.Locale; -import java.util.concurrent.Executor; - import javax.annotation.Nonnull; import javax.inject.Inject; import javax.inject.Named; +import java.util.Locale; +import java.util.concurrent.Executor; public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -143,11 +137,7 @@ public class CalculatorApplication extends android.app.Application implements Sh languages.updateContextLocale(this, true); App.getGa().reportInitially(preferences); - Locator.getInstance().init(calculator, - engine, - keyboard, - new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator)) - ); + Locator.getInstance().init(calculator, engine, keyboard); calculator.init(initThread); diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java index bcb1b3c7..eb96f33d 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java @@ -22,16 +22,13 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.plot.CalculatorPlotter; - import javax.annotation.Nonnull; public interface CalculatorLocator { void init(@Nonnull Calculator calculator, @Nonnull Engine engine, - @Nonnull Keyboard keyboard, - @Nonnull CalculatorPlotter plotter); + @Nonnull Keyboard keyboard); @Nonnull Calculator getCalculator(); @@ -42,6 +39,4 @@ public interface CalculatorLocator { @Nonnull Keyboard getKeyboard(); - @Nonnull - CalculatorPlotter getPlotter(); } diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorUtils.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorUtils.java index f855719a..862b5f9e 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorUtils.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorUtils.java @@ -22,15 +22,6 @@ package org.solovyev.android.calculator; -import jscl.math.Generic; -import jscl.math.function.Constant; -import jscl.math.function.IConstant; - -import java.util.HashSet; -import java.util.Set; - -import javax.annotation.Nonnull; - /** * User: serso * Date: 9/22/12 @@ -42,18 +33,4 @@ public final class CalculatorUtils { throw new AssertionError(); } - @Nonnull - public static Set getNotSystemConstants(@Nonnull Generic expression) { - final Set notSystemConstants = new HashSet(); - - for (Constant constant : expression.getConstants()) { - IConstant var = Locator.getInstance().getEngine().getVariablesRegistry().get(constant.getName()); - if (var != null && !var.isSystem() && !var.isDefined()) { - notSystemConstants.add(constant); - } - } - - return notSystemConstants; - } - } diff --git a/app/src/main/java/org/solovyev/android/calculator/Display.java b/app/src/main/java/org/solovyev/android/calculator/Display.java index 7f24cb41..0898b7ce 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Display.java +++ b/app/src/main/java/org/solovyev/android/calculator/Display.java @@ -57,8 +57,6 @@ public class Display { Lazy notifier; @Inject Lazy preferredPreferences; - @Inject - ActivityLauncher launcher; @Nullable private DisplayView view; @Nonnull diff --git a/app/src/main/java/org/solovyev/android/calculator/DisplayFragment.java b/app/src/main/java/org/solovyev/android/calculator/DisplayFragment.java index 844a2085..539e47de 100644 --- a/app/src/main/java/org/solovyev/android/calculator/DisplayFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/DisplayFragment.java @@ -37,17 +37,12 @@ import butterknife.ButterKnife; import com.squareup.otto.Bus; import jscl.NumeralBase; import jscl.math.Generic; -import jscl.math.function.Constant; -import jscl.math.function.CustomFunction; import org.solovyev.android.calculator.converter.ConverterFragment; import org.solovyev.android.calculator.jscl.JsclOperation; -import org.solovyev.android.calculator.plot.ExpressionFunction; import org.solovyev.android.plotter.Plotter; import javax.annotation.Nonnull; import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; public class DisplayFragment extends BaseFragment implements View.OnClickListener, MenuItem.OnMenuItemClickListener { @@ -146,8 +141,7 @@ public class DisplayFragment extends BaseFragment implements View.OnClickListene addMenu(menu, R.string.c_convert, this); } } - final int parameters = CalculatorUtils.getNotSystemConstants(result).size(); - if (parameters >= 0 && parameters <= 2) { + if (launcher.canPlot(result)) { addMenu(menu, R.string.c_plot, this); } } @@ -216,21 +210,7 @@ public class DisplayFragment extends BaseFragment implements View.OnClickListene ConverterFragment.show(getActivity(), getValue(result)); return true; case R.string.c_plot: - if (result != null) { - try { - final List parameters = new ArrayList<>(); - for (Constant parameter : CalculatorUtils.getNotSystemConstants(result)) { - parameters.add(parameter.getName()); - } - new CustomFunction.Builder().setParameterNames(parameters).setContent(state.text).create(); - final CustomFunction f = new CustomFunction.Builder().setName("").setParameterNames(parameters).setContent(result.toString()).create(); - final ExpressionFunction ef = new ExpressionFunction(f, false); - plotter.add(ef); - launcher.showPlotter(); - } catch (RuntimeException e) { - errorReporter.onException(e); - } - } + launcher.plot(result); return true; default: return false; diff --git a/app/src/main/java/org/solovyev/android/calculator/Locator.java b/app/src/main/java/org/solovyev/android/calculator/Locator.java index bdd4112b..e8213d21 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Locator.java +++ b/app/src/main/java/org/solovyev/android/calculator/Locator.java @@ -22,8 +22,6 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.plot.CalculatorPlotter; - import javax.annotation.Nonnull; public class Locator implements CalculatorLocator { @@ -36,8 +34,6 @@ public class Locator implements CalculatorLocator { private Calculator calculator; @Nonnull private Keyboard keyboard; - @Nonnull - private CalculatorPlotter calculatorPlotter; public Locator() { } @@ -50,13 +46,10 @@ public class Locator implements CalculatorLocator { @Override public void init(@Nonnull Calculator calculator, @Nonnull Engine engine, - @Nonnull Keyboard keyboard, - @Nonnull CalculatorPlotter plotter) { + @Nonnull Keyboard keyboard) { this.calculator = calculator; this.engine = engine; - this.calculatorPlotter = plotter; - this.keyboard = keyboard; } @@ -78,9 +71,4 @@ public class Locator implements CalculatorLocator { return keyboard; } - @Nonnull - @Override - public CalculatorPlotter getPlotter() { - return calculatorPlotter; - } } diff --git a/app/src/main/java/org/solovyev/android/calculator/Notifier.java b/app/src/main/java/org/solovyev/android/calculator/Notifier.java index 897b54d8..5f7f7802 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Notifier.java +++ b/app/src/main/java/org/solovyev/android/calculator/Notifier.java @@ -24,17 +24,14 @@ package org.solovyev.android.calculator; import android.app.Application; import android.os.Handler; +import android.support.annotation.StringRes; import android.widget.Toast; import org.solovyev.android.Threads; -import org.solovyev.android.msg.AndroidMessage; import org.solovyev.common.msg.Message; -import org.solovyev.common.msg.MessageType; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; @Singleton public class Notifier { @@ -48,27 +45,27 @@ public class Notifier { } public void showMessage(@Nonnull Message message) { - showMessageInUiThread(message.getLocalizedMessage()); + showMessage(message.getLocalizedMessage()); } - public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List parameters) { - showMessage(new AndroidMessage(messageCode, messageType, application, parameters)); + public void showMessage(@StringRes int message, Object... parameters) { + showMessage(application.getString(message, parameters)); } - public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) { - showMessage(new AndroidMessage(messageCode, messageType, application, parameters)); + public void showMessage(@StringRes int message) { + showMessage(application.getString(message)); } - private void showMessageInUiThread(@Nonnull final String message) { + public void showMessage(@Nonnull final String message) { if (Threads.isUiThread()) { Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); - } else { - handler.post(new Runnable() { - @Override - public void run() { - Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); - } - }); + return; } + handler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); + } + }); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java b/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java index 29a96119..d1b30277 100644 --- a/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java +++ b/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java @@ -1,13 +1,5 @@ package org.solovyev.android.calculator.keyboard; -import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING; -import static android.view.HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING; -import static android.view.HapticFeedbackConstants.KEYBOARD_TAP; -import static org.solovyev.android.calculator.App.cast; -import static org.solovyev.android.calculator.App.getScreenMetrics; -import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; -import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile; - import android.app.Activity; import android.app.Application; import android.content.Context; @@ -20,15 +12,8 @@ import android.util.TypedValue; import android.view.View; import android.widget.ImageView; import android.widget.TextView; - import org.solovyev.android.Views; -import org.solovyev.android.calculator.ActivityUi; -import org.solovyev.android.calculator.App; -import org.solovyev.android.calculator.Calculator; -import org.solovyev.android.calculator.Editor; -import org.solovyev.android.calculator.Keyboard; -import org.solovyev.android.calculator.Preferences; -import org.solovyev.android.calculator.PreferredPreferences; +import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.buttons.CppSpecialButton; import org.solovyev.android.calculator.view.ScreenMetrics; import org.solovyev.android.views.Adjuster; @@ -37,11 +22,16 @@ import org.solovyev.android.views.dragbutton.DragButton; import org.solovyev.android.views.dragbutton.DragDirection; import org.solovyev.android.views.dragbutton.SimpleDragListener; +import javax.annotation.Nonnull; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nonnull; -import javax.inject.Inject; +import static android.view.HapticFeedbackConstants.*; +import static org.solovyev.android.calculator.App.cast; +import static org.solovyev.android.calculator.App.getScreenMetrics; +import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; +import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile; public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPreferenceChangeListener, SimpleDragListener.DragProcessor, View.OnClickListener { @@ -67,6 +57,8 @@ public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPrefer @Inject Calculator calculator; @Inject + ActivityLauncher launcher; + @Inject PreferredPreferences preferredPreferences; protected int orientation = Configuration.ORIENTATION_PORTRAIT; private int textSize; diff --git a/app/src/main/java/org/solovyev/android/calculator/keyboard/PartialKeyboardUi.java b/app/src/main/java/org/solovyev/android/calculator/keyboard/PartialKeyboardUi.java index 44b88e15..90690310 100644 --- a/app/src/main/java/org/solovyev/android/calculator/keyboard/PartialKeyboardUi.java +++ b/app/src/main/java/org/solovyev/android/calculator/keyboard/PartialKeyboardUi.java @@ -17,7 +17,6 @@ import butterknife.Bind; import butterknife.ButterKnife; import jscl.NumeralBase; import org.solovyev.android.Check; -import org.solovyev.android.calculator.ActivityLauncher; import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.R; @@ -121,7 +120,7 @@ public class PartialKeyboardUi extends BaseKeyboardUi { return true; case R.id.cpp_button_equals: if (direction == down) { - ActivityLauncher.tryPlot(); + launcher.plotDisplayedExpression(); return true; } else if (direction == up) { calculator.simplify(); diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java b/app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java deleted file mode 100644 index 28e2f872..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotterImpl.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.plot; - -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import jscl.math.Generic; -import jscl.math.function.Constant; -import org.solovyev.android.calculator.Calculator; -import org.solovyev.android.calculator.CalculatorEventType; -import org.solovyev.android.calculator.CalculatorUtils; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class CalculatorPlotterImpl implements CalculatorPlotter { - - @Nonnull - private final List functions = new ArrayList(); - - @Nonnull - private final Calculator calculator; - - private final PlotResourceManager resourceManager = new MapPlotResourceManager(); - - private boolean plot3d = false; - private boolean adjustYAxis = true; - - private boolean plotImag = false; - - private int arity = 0; - - @Nonnull - private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance(); - - @Nonnull - private PlotData plotData = new PlotData(Collections.emptyList(), plot3d, true, plotBoundaries); - - public CalculatorPlotterImpl(@Nonnull Calculator calculator) { - this.calculator = calculator; - } - - @Nonnull - @Override - public PlotData getPlotData() { - return plotData; - } - - @Override - public boolean addFunction(@Nonnull Generic expression) { - final List variables = new ArrayList(CalculatorUtils.getNotSystemConstants(expression)); - - if (variables.size() > 2) throw new AssertionError(); - - final Constant xVariable; - if (variables.size() > 0) { - xVariable = variables.get(0); - } else { - xVariable = null; - } - - final Constant yVariable; - if (variables.size() > 1) { - yVariable = variables.get(1); - } else { - yVariable = null; - } - - final XyFunction realXyFunction = new XyFunction(expression, xVariable, yVariable, false); - final XyFunction imagXyFunction = new XyFunction(expression, xVariable, yVariable, true); - - // first create plot functions with default line definitions - PlotFunction realPlotFunction = new PlotFunction(realXyFunction); - PlotFunction imagPlotFunction = new PlotFunction(imagXyFunction); - - // then remove all unpinned graphs and free their line definitions - removeAllUnpinnedExcept(realPlotFunction, imagPlotFunction); - - // create plot functions with freed line definitions - realPlotFunction = newPlotFunction(realXyFunction); - imagPlotFunction = newPlotFunction(imagXyFunction); - - final boolean realAdded = addFunction(realPlotFunction); - final boolean imagAdded = addFunction(plotImag ? imagPlotFunction : PlotFunction.invisible(imagPlotFunction)); - - return imagAdded || realAdded; - } - - @Nonnull - private PlotFunction newPlotFunction(@Nonnull XyFunction xyFunction) { - return new PlotFunction(xyFunction, resourceManager.generateAndRegister()); - } - - @Override - public boolean addFunction(@Nonnull PlotFunction plotFunction) { - synchronized (functions) { - if (!functions.contains(plotFunction)) { - resourceManager.register(plotFunction.getPlotLineDef()); - functions.add(plotFunction); - onFunctionsChanged(); - return true; - } else { - return false; - } - } - } - - private boolean removeAllUnpinnedExcept(@Nonnull final PlotFunction... exceptFunctions) { - synchronized (functions) { - - boolean changed = Iterables.removeIf(functions, new Predicate() { - @Override - public boolean apply(@Nullable PlotFunction function) { - if (function != null && !function.isPinned()) { - - for (PlotFunction exceptFunction : exceptFunctions) { - if (exceptFunction.equals(function)) { - return false; - } - } - - resourceManager.unregister(function.getPlotLineDef()); - - return true; - } else { - return false; - } - } - }); - - if (changed) { - onFunctionsChanged(); - } - - return changed; - } - } - - - @Override - public void removeAllUnpinned() { - synchronized (functions) { - boolean changed = Iterables.removeIf(functions, new Predicate() { - @Override - public boolean apply(@Nullable PlotFunction function) { - boolean removed = function != null && !function.isPinned(); - - if (removed) { - resourceManager.unregister(function.getPlotLineDef()); - } - - return removed; - } - }); - - if (changed) { - onFunctionsChanged(); - } - } - } - - @Override - public boolean removeFunction(@Nonnull PlotFunction plotFunction) { - synchronized (functions) { - boolean changed = functions.remove(plotFunction); - if (changed) { - resourceManager.unregister(plotFunction.getPlotLineDef()); - onFunctionsChanged(); - } - return changed; - } - } - - @Override - public boolean addFunction(@Nonnull XyFunction xyFunction) { - return addFunction(newPlotFunction(xyFunction)); - } - - @Override - public boolean addFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) { - return addFunction(new PlotFunction(xyFunction, functionLineDef)); - } - - @Override - public boolean updateFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) { - final PlotFunction newFunction = new PlotFunction(xyFunction, functionLineDef); - - return updateFunction(newFunction); - } - - @Override - public boolean updateFunction(@Nonnull PlotFunction newFunction) { - boolean changed = updateFunction0(newFunction); - if (changed) { - firePlotDataChangedEvent(); - } - return changed; - } - - public boolean updateFunction0(@Nonnull PlotFunction newFunction) { - boolean changed = false; - - synchronized (functions) { - for (int i = 0; i < functions.size(); i++) { - final PlotFunction oldFunction = functions.get(i); - if (oldFunction.equals(newFunction)) { - - resourceManager.unregister(oldFunction.getPlotLineDef()); - resourceManager.register(newFunction.getPlotLineDef()); - - // update old function - functions.set(i, newFunction); - changed = true; - break; - } - } - } - - return changed; - } - - @Override - public boolean removeFunction(@Nonnull XyFunction xyFunction) { - return removeFunction(new PlotFunction(xyFunction)); - } - - @Nonnull - @Override - public PlotFunction pin(@Nonnull PlotFunction plotFunction) { - final PlotFunction newFunction = PlotFunction.pin(plotFunction); - updateFunction0(newFunction); - return newFunction; - } - - @Nonnull - @Override - public PlotFunction unpin(@Nonnull PlotFunction plotFunction) { - final PlotFunction newFunction = PlotFunction.unpin(plotFunction); - updateFunction0(newFunction); - return newFunction; - } - - @Nonnull - @Override - public PlotFunction show(@Nonnull PlotFunction plotFunction) { - final PlotFunction newFunction = PlotFunction.visible(plotFunction); - - updateFunction(newFunction); - - return newFunction; - } - - @Nonnull - @Override - public PlotFunction hide(@Nonnull PlotFunction plotFunction) { - final PlotFunction newFunction = PlotFunction.invisible(plotFunction); - - updateFunction(newFunction); - - return newFunction; - } - - @Override - public void clearAllFunctions() { - synchronized (functions) { - resourceManager.unregisterAll(); - functions.clear(); - onFunctionsChanged(); - } - } - - @Nullable - @Override - public PlotFunction getFunctionById(@Nonnull final String functionId) { - synchronized (functions) { - return Iterables.find(functions, new Predicate() { - @Override - public boolean apply(@Nullable PlotFunction function) { - return function != null && function.getXyFunction().getId().equals(functionId); - } - }, null); - } - } - - // NOTE: this method must be called from synchronized block - private void onFunctionsChanged() { - if (!Thread.holdsLock(functions)) throw new AssertionError(); - - int maxArity = 0; - for (PlotFunction function : functions) { - final XyFunction xyFunction = function.getXyFunction(); - - maxArity = Math.max(maxArity, xyFunction.getArity()); - } - - plot3d = maxArity > 1; - - if (functions.isEmpty()) { - // no functions => new plot => default boundaries - this.plotBoundaries = PlotBoundaries.newDefaultInstance(); - this.adjustYAxis = true; - } - - arity = maxArity; - - firePlotDataChangedEvent(); - } - - @Nonnull - @Override - public List getFunctions() { - synchronized (functions) { - return new ArrayList(functions); - } - } - - @Nonnull - @Override - public List getVisibleFunctions() { - synchronized (functions) { - return Lists.newArrayList(Iterables.filter(functions, new Predicate() { - @Override - public boolean apply(@Nullable PlotFunction function) { - return function != null && function.isVisible(); - } - })); - } - } - - @Override - public void plot() { - calculator.fireCalculatorEvent(CalculatorEventType.plot_graph, null); - } - - @Override - public void plot(@Nonnull Generic expression) { - addFunction(expression); - plot(); - } - - @Override - public boolean is2dPlotPossible() { - return arity < 2; - } - - @Override - public boolean isPlotPossibleFor(@Nonnull Generic expression) { - boolean result = false; - - int size = CalculatorUtils.getNotSystemConstants(expression).size(); - if (size == 0 || size == 1 || size == 2) { - result = true; - } - - return result; - } - - @Override - public void setPlot3d(boolean plot3d) { - if (this.plot3d != plot3d) { - this.plot3d = plot3d; - firePlotDataChangedEvent(); - } - } - - private void firePlotDataChangedEvent() { - updatePlotData(); - calculator.fireCalculatorEvent(CalculatorEventType.plot_data_changed, plotData); - } - - private void updatePlotData() { - plotData = new PlotData(getVisibleFunctions(), plot3d, adjustYAxis, plotBoundaries); - } - - @Override - public void setPlotImag(boolean plotImag) { - if (this.plotImag != plotImag) { - this.plotImag = plotImag; - if (toggleImagFunctions(this.plotImag)) { - firePlotDataChangedEvent(); - } - } - } - - @Override - public void savePlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) { - if (!this.plotBoundaries.equals(plotBoundaries)) { - this.plotBoundaries = plotBoundaries; - this.adjustYAxis = false; - updatePlotData(); - } - } - - @Override - public void setPlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) { - if (!this.plotBoundaries.equals(plotBoundaries)) { - this.plotBoundaries = plotBoundaries; - this.adjustYAxis = false; - firePlotDataChangedEvent(); - } - } - - private boolean toggleImagFunctions(boolean show) { - boolean changed = false; - - synchronized (functions) { - for (int i = 0; i < functions.size(); i++) { - final PlotFunction plotFunction = functions.get(i); - if (plotFunction.getXyFunction().isImag()) { - functions.set(i, show ? PlotFunction.visible(plotFunction) : PlotFunction.invisible(plotFunction)); - changed = true; - } - } - } - - return changed; - } -} diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionListItem.java b/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionListItem.java deleted file mode 100644 index 9004b7e6..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionListItem.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.plot; - -import android.content.Context; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ImageButton; -import android.widget.TextView; - -import org.solovyev.android.calculator.Locator; -import org.solovyev.android.calculator.R; -import org.solovyev.android.list.ListItem; -import org.solovyev.android.view.ViewBuilder; -import org.solovyev.android.view.ViewFromLayoutBuilder; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class PlotFunctionListItem implements ListItem { - - private static final String PREFIX = "plot_function_"; - - @Nonnull - private PlotFunction plotFunction; - - @Nonnull - private ViewBuilder viewBuilder; - - @Nonnull - private String tag; - - public PlotFunctionListItem(@Nonnull PlotFunction plotFunction) { - this.plotFunction = plotFunction; - this.viewBuilder = ViewFromLayoutBuilder.newInstance(R.layout.cpp_plot_function_list_item); - this.tag = PREFIX + plotFunction.getXyFunction().getExpressionString(); - } - - @Nullable - @Override - public OnClickAction getOnClickAction() { - return null; - } - - @Nullable - @Override - public OnClickAction getOnLongClickAction() { - return null; - } - - @Nonnull - @Override - public View updateView(@Nonnull Context context, @Nonnull View view) { - final Object viewTag = view.getTag(); - if (viewTag instanceof String) { - if (this.tag.equals(viewTag)) { - return view; - } else if (((String) viewTag).startsWith(PREFIX)) { - fillView(view, context); - return view; - } else { - return build(context); - } - } - - return build(context); - } - - @Nonnull - @Override - public View build(@Nonnull Context context) { - final View root = buildView(context); - fillView(root, context); - return root; - } - - private View buildView(@Nonnull Context context) { - return viewBuilder.build(context); - } - - private void fillView(@Nonnull View root, @Nonnull final Context context) { - root.setTag(tag); - - final CalculatorPlotter plotter = Locator.getInstance().getPlotter(); - - final TextView expressionTextView = (TextView) root.findViewById(R.id.cpp_plot_function_expression_textview); - expressionTextView.setText(plotFunction.getXyFunction().getExpressionString()); - - final CheckBox pinnedCheckBox = (CheckBox) root.findViewById(R.id.cpp_plot_function_pinned_checkbox); - pinnedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean pin) { - if (pin) { - if (!plotFunction.isPinned()) { - plotFunction = plotter.pin(plotFunction); - } - } else { - if (plotFunction.isPinned()) { - plotFunction = plotter.unpin(plotFunction); - } - } - } - }); - pinnedCheckBox.setChecked(plotFunction.isPinned()); - - final CheckBox visibleCheckBox = (CheckBox) root.findViewById(R.id.cpp_plot_function_visible_checkbox); - visibleCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean show) { - if (show) { - if (!plotFunction.isVisible()) { - plotFunction = plotter.show(plotFunction); - } - } else { - if (plotFunction.isVisible()) { - plotFunction = plotter.hide(plotFunction); - } - } - } - }); - visibleCheckBox.setChecked(plotFunction.isVisible()); - - final ImageButton settingsButton = (ImageButton) root.findViewById(R.id.cpp_plot_function_settings_button); - settingsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // FIXME: 2016-02-01 - } - }); - } -} diff --git a/app/src/test/java/org/solovyev/android/calculator/AbstractCalculatorTest.java b/app/src/test/java/org/solovyev/android/calculator/AbstractCalculatorTest.java index e8465f3b..43ebd09a 100644 --- a/app/src/test/java/org/solovyev/android/calculator/AbstractCalculatorTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/AbstractCalculatorTest.java @@ -24,7 +24,6 @@ package org.solovyev.android.calculator; import android.content.SharedPreferences; import com.squareup.otto.Bus; -import org.solovyev.android.calculator.plot.CalculatorPlotter; import java.util.concurrent.Executor; @@ -38,7 +37,7 @@ import static org.mockito.Mockito.mock; public class AbstractCalculatorTest { protected void setUp() throws Exception { - Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class)); + Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), mock(Keyboard.class)); Locator.getInstance().getEngine().init(new Executor() { @Override public void execute(Runnable command) { diff --git a/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java b/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java index a312494d..ad99c36d 100644 --- a/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java +++ b/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java @@ -36,7 +36,6 @@ import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.operators.OperatorsRegistry; import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry; -import org.solovyev.android.calculator.plot.CalculatorPlotter; import jscl.JsclMathEngine; @@ -68,7 +67,7 @@ public class CalculatorTestUtils { public static void staticSetUp() throws Exception { App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap>(), "test", 0))); - Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class)); + Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class)); Locator.getInstance().getEngine().init(new Executor() { @Override public void execute(Runnable command) { @@ -83,7 +82,7 @@ public class CalculatorTestUtils { } public static void staticSetUp(@Nullable Context context) throws Exception { - Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class)); + Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class)); Locator.getInstance().getEngine().init(new Executor() { @Override public void execute(Runnable command) { diff --git a/jscl/src/main/java/jscl/math/Generic.java b/jscl/src/main/java/jscl/math/Generic.java index 0c3addc1..fa5acaec 100644 --- a/jscl/src/main/java/jscl/math/Generic.java +++ b/jscl/src/main/java/jscl/math/Generic.java @@ -1,17 +1,40 @@ package jscl.math; import jscl.math.function.Constant; +import jscl.math.function.IConstant; import jscl.mathml.MathML; import jscl.text.ParserUtils; - -import java.math.BigInteger; -import java.util.Set; +import org.solovyev.common.math.MathRegistry; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; public abstract class Generic implements Arithmetic, Comparable { + @Nonnull + public Set getUndefinedConstants(@Nonnull MathRegistry constantsRegistry) { + final Set result = new HashSet<>(); + + for (Constant expressionConstant : getConstants()) { + final IConstant registryConstant = constantsRegistry.get(expressionConstant.getName()); + if (registryConstant == null) { + continue; + } + if (registryConstant.isSystem()) { + continue; + } + if(registryConstant.isDefined()) { + continue; + } + result.add(expressionConstant); + } + + return result; + } + public BigInteger toBigInteger() { return null; } diff --git a/jscl/src/main/java/jscl/math/function/CustomFunction.java b/jscl/src/main/java/jscl/math/function/CustomFunction.java index fbda2ad6..175e3547 100644 --- a/jscl/src/main/java/jscl/math/function/CustomFunction.java +++ b/jscl/src/main/java/jscl/math/function/CustomFunction.java @@ -43,7 +43,7 @@ public class CustomFunction extends Function implements IFunction { private CustomFunction(@Nonnull String name, @Nonnull List parameterNames, @Nonnull String content, - @Nullable String description) { + @Nullable String description) throws CustomFunctionCalculationException { super(name, new Generic[parameterNames.size()]); this.parameterNames = parameterNames; try { @@ -321,7 +321,7 @@ public class CustomFunction extends Function implements IFunction { } @Nonnull - public CustomFunction create() { + public CustomFunction create() throws CustomFunctionCalculationException { final CustomFunction customFunction = new CustomFunction(name, parameterNames, prepareContent(content), description); customFunction.setSystem(system); if (id != null) {